第一期:前端九條bug分享

開發過程中bug常相伴, 不能修復或者無法復現就忽略這些問題, 所以計劃每當我遇到9個有價值有思考的bug就會統一分享出來, 以此來擴展性的思考工作本身, 不斷的提高自己的意識, 畢竟能力的提高遇到的bug一定不同, 而且如果遇到bug越來越少只能說明自己的工作任務與學習任務在'原地踏步,且不飽和', 既然如此就靠bug來見證自己的成長吧.

1: element-ui: el-card標籤

bug現象:有一天測試突然跟我說, 一個當前版本根本沒動過的頁面發生bug, 頁面有些數據為空, 有些按鈕點擊無效.

bug追查:第一分析: 那好吧根本沒動過的頁面出問題那就是歷史遺留問題或者後端返回出了問題, 那就去排查一番吧,但是排查的過程令我傻眼, 後臺返回了值但是莫名其妙的一直在報'空值'的錯, 而且這是一個三年的老項目還是其他項目組轉過來了, 說實話代碼很爛很亂, 使用了大量的mixin還有部分邏輯進入了node_modules裡面還沒有文檔, 這個時候只能暴力破解了, 打個debugger一步一步的追查下去, 真的定位了很久發現了關鍵點, 是某個子組件沒有得到傳值, 然後這個子組件還會往父組件傳一個值, 這才導致了父組件裡面的某些值為空從而報錯, 看了看向線上的項目沒有這些問題, 這有我這個版本有問題那麼一定是有人動了這一頁的代碼, 或者整體環境的某個全局屬性被篡改了那問題涉及就廣了, 調出gitlab當前頁的上一個版本代碼,(這裡是一個小技巧)把當前代碼commit, 生成緩存然後把上個版本的代碼覆蓋當前代碼, 在deff裡面就可以看到兩版本代碼的差異了, 我發現原本根標籤是

...

, 而這次的是, 思維有點堵塞:就換了個標籤而已, 不涉及任何的屬性與變量, 怎麼可能導致數據崩潰??

bug原因:罪魁禍首是這個this.$parent, 原來上一個同學在組件裡面是通過父級組件的實例來獲取父級傳過來的數據的, 那麼問題明瞭了標籤成為了他的父級, 那麼它理所當然的取不到更上一級的數據了, 所以獲取到的數據就是空的,'兇手'就是它.

bug解決:

  1. 改this.$parent為'行間傳值'的形式, 並測試是否好用.
  2. 尋找全局是否還有類似的情況, 一一改正.
  3. 找到添加的同學, 說明原因, 以及詢問他是否還如此改變過其他地方的代碼, 放棄其他工程也出現類型的情況.


bug思考:this.$parent或者是 this.$children這種方式獲取與傳遞數據十分不妥, 因為沒有明確數據來源與使用者, 這樣就會導致除了問題很難排查, 這種"父與子"的關係很脆弱,很容易突然'父組件'變成爺爺組件了, bug也就隨之而來, 所以不是不得已的情況下或是高度封裝的環境下, 不推薦使用.隨意的改變一塊代碼, 你的知識範圍裡面感覺沒有影響,但不代表就真的沒有影響, 不要忽視"驗證"這個環節, 自己寫的代碼自己需要負責任ok?

2: antv: 折線圖倒敘

bug現象:之前使用公司二次封裝的echarts開發, 這個版本使用了antv來開發圖表, 但是怪異的事情出現了, 折線圖的'y軸'出現了倒敘的現象, 也就是 10, 5, 0 這種怪異的排列, 導致圖表上下顛倒.bug追查:之前沒有類似問題, 這個版本才出現, 這個版本後端沒有動接口, 那麼問題就在這個組件的使用上, 第一分析: 是否有這樣一個屬性, 控制了y軸的正反? 去看文檔沒有找到, 第二分析: 去看官網的實例, 一個字母都不差的拷貝過來但還是反的, 第三分析: 那麼問題出在數據上, 但是數據沒有變換, 那麼問題出在兩套插件處理數據的機制上, 仔細觀察再仔細觀察, 發現了!原來後臺返回的數字是'字符串類型的'.bug原因:原來antv只會對'number'進行從小到大的排序, 漢字的話就按接收順序顯示了, 我把組數據都+一下就ok了bug思考:不同組件庫對數據的處理形式也是不同的, 不要以為換了個組件庫知識變動api的方法就可以了, 還會有很多'原罪'.通過使用三套不同的圖表庫, 使我受益匪淺, 並不是圖表絢麗的效果, 而是對每種圖表調用方式的思考, 讓我更深入的理解設計模式.3: 正則: 前瞻性匹配vs火狐

bug現象:

項目突然無法在火狐,ie瀏覽器上運行,當然項目只需要在谷歌瀏覽器運行, 但是這個現象我還是想探究一下.bug追查:本次排查順序不太對, 我先看上個版本是否都可以在火狐運行, 發現上個版本沒問題那就把問題定位在當前版本, 其實應該先看控制檯報錯, 但是由於頁面是空白的理所當然的認為完全崩潰了, 或者是後臺返回錯了, (下次一定先追查控制檯的報錯信息) 也就是這一段"SyntaxError: invalid regexp group", 是前瞻性匹配出了問題, 我在為數值加千分號的過濾器上使用瞭如下的代碼, (其實我自己寫的是翻轉字符串逢3位加',')

<code>

export

default

{ install(vm) { vm.filter(

'formatThousand'

,

(

num

) =>

{

if

(!num)

return

0

;

const

reg =

/\d{1,3}(?=(\d{3})+$)/g

;

return

(

`

${num}

`

).replace(reg,

'$&,'

); }); },};/<code>

那麼註釋掉這個代碼就不報錯了麼?答案是否定的, 報錯仍然在繼續, 我打開vscode的搜索臺, 輸入了前瞻性匹配的語法, 但是啥也搜不到, 思考....vscode搜索臺也是有侷限的, 比如他不會深入到node_modules裡面查找, 這樣也是為了性能, 那麼一定是這次新引入的插件除了問題, 經過查找果然是因為我們自己公司製作的'3d視圖'組件使用了正則的前瞻匹配, 但是為了更好的推進公司技術的發展還必須使用公司的技術, 那麼現在不是抱怨而是反饋, 把這個問題與可視化部門明確, 還好當前項目本就不用刻意兼容火狐但是其他項目要注意嘍.啥是前瞻性匹配:正則是js基礎, 如果不熟練的同學需要反省了,?還可以解除貪婪模式(?=exp)匹配後面滿足表達式exp的位置(?!exp)匹配後面不滿足表達式exp的位置bug原因:原來ie與火狐瀏覽器並不支持前瞻性匹配bug思考:

很多時候我們會忽略某些方法的兼容性, 甚至某些插件沒有照顧兼容性, 那麼選技術的時候一定要根據項目要求而定. 若是我們自己開發插件也要寫好兼容範圍方便大家使用.

4: scss: 引入scss文件無效

bug現象:需要全局改變table相關的樣式, 我單獨抽出了個scss文件放在最外層, 但是怪異的事情發生了, scss文件裡面的嵌套寫法不生效, 必須要拿出來像css文件一樣的寫法才生效bug追查:定位問題:嵌套的寫法無效, 那麼變量是否有效?答案是也無效, 那就是說我引入了scss文件沒問題, 系統也解析, 但是scss的寫法系統不認識, 那麼難道是我的scss-loader壞了?? 每個vue文件裡面寫上lang='scss'都是沒問題的, 那麼找之前的工程的引入方式複製粘貼,還是不行....bug原因:css的引入兩種方式, 有一種是scss提供的如下:使用第二種方式可以正確的解析scss文件

<code>

@import

url(

'./assets/style/animation.css'

); /<code>
<code>

@import

'@/assets/style/animation.scss'

; /<code>

bug思考:不要小瞧引入方式.編寫項目css是非常重要的一部分, 主要有'ben'與'oocss'兩種思想,有的人直接把css寫在html文件裡面, 也有人直接寫在 app.vue文件裡面不加'scoped'就是全局的模式了, 這些當然都沒問題,但是畢竟我們是有追求的工程師, 要做到'美觀'與'工程化', '色香味俱全'才是好的代碼.

5: vue: 文件夾不要叫bin

bug現象:我上一篇文章裡面分享瞭如何在項目裡面做mock的工程化, 但是吧mock工程放入某些工程之後出現了怪異的錯誤, 首先可以正常啟動, 8080端口也啟動成功, 但是...瀏覽器訪問的一瞬間就會終止localhost的服務, 強制退出可還行??bug追查:說實話第一時間腦海空白, 具體的原因想不通, 反覆試驗了幾次之後確定了bug的具體現象, 在每個操作處打debugger, 仍然追查不到原因, 但是報錯都是在bin這個文件夾裡面, 裡面的文件也都沒問題正常的執行, 那麼會不會是這個bin文件夾本身有問題, 改個名字試試? 還真就好了~~bug原因:bin這個文件名比較特殊, 改成其他的立刻就好了bug思考:不要輕易使用系統常用文件名, 之前有一次寫我自己的ccpack也是js的index文件與node環境的index文件衝突, 不可以都叫index...., 起名也要謹慎啊.

6: token: 儲存在哪裡比較好?

bug現象:我們的token一直都是存在cookie裡面, 可是最近在深入學習web安全相關知識, 感覺這樣並不一定對.bug原因:csrf攻擊如下: 你在a網站登錄成功, b是釣魚網站, 你點擊b的時候會向a網站發送請求冒充你本人的請求, 這個時候瀏覽器會默認帶上你在a網站登錄的cookie信息發送過去, 而這個請求不光利用img標籤進行get請求, 還可以利用form表單進行post請求, 所以這個token不能放在cookie這種位置吧, 而且還不是httponly, 更合理的是放在local storage裡面, 每次請求附加在header上面, 並且隨時準備更新它,這樣csrf的時候是取不到local storage的值的.bug問題反饋:與相關同學交流了這個問題, 因為在cookie加上token是後端直接操作的, 但是由於這個問題後端同學已經封裝在統一的中間件裡面, 要是修改的話涉及面有一些廣, 但是其他的方式可以起到補救的效果, 比如驗證referer 來源信息, 白名單, 二次驗證等等.在這個問題上得到的啟示是, 很多核心的邏輯不可以草草就制定, 而且能做到更好為什麼不做那?


7: pm2: restart並不靠譜

bug起因:現在服務端渲染的項目也不少, 前端工程師大部分都是使用node來做的, 線程保護方面大部分也是選用pm2, 畢竟pm2簡潔明瞭還自帶'負載均衡'bug現象:在本地與test環境都沒問題, 上線的晚上我執行了以下操作

<code>

sudo

-s

cd

/home/xxxx/xxxx/ // 線上環境目錄git pull

npm

run build

pm2

restart all

/<code>

但是奇怪的事情發生了, 啟動的時候都是'成功', 過了2秒鐘, 其中四個server變成了error, (為什麼是4個server, 因為分配了四核)我重新build項目, 再次pm2 restart all仍然無效, bug來了開始本該興奮, 但是奈何正在上線項目大家都很急,那就需要緊張起來了, 先看onerror日誌因為在服務器環境所以只能cat看, 但是日誌一團亂麻看了一會沒有找到真正的原因, 難道是build出了大問題?test是好的啊, 當時陷入了反覆build與restart的傻操作, 冷靜一下和這個問題有沒有可能不是打包錯誤而是服務錯誤? 問題不在我們的代碼而是在pm2本身出現了衝突之類的, 那好假設'restart重啟'不能解決問題, 那我直接 pm2 delete id 這樣刪除掉4個server, 然後 pm2 start ./server.js -i 4重新啟動還真就ok了.

bug分析:遇到事情從自己身上找原因是好的品質, 但是不可以只侷限在懷疑自己, 也要考慮也許是其他技術出了問題.pm2也只是個系統, 偶爾不是重啟他監控的項目而是重啟它本身.

8: vue: $變量的用處

bug起因:公司的3d技術團隊開發的一套組件, 在接收實例的時候命名必須是'$a'不可以是'a'.請教了可視化團隊的同學, 得知$與_開頭的變量不會被vue監控, 這樣這個變量我們可以自己來監控, 更加的靈活.使用$:在data裡面定義$txt變量並且在行間{{$txt}}報錯如下:

<code>`Property "$txt" must be accessed 

with

"$data.$txt"

because properties

starting

with

"$"

or

"_"

are

not

proxied

in

the Vue

instance

to

prevent conflicts

with

Vue internals.

`

/<code>

必須使用“$data.$txt”訪問屬性'$txt',因為在Vue實例中不代理以 "$" or "_"開頭的屬性,以防止與Vue內部發生衝突。

使用_:在data裡面定義_txt變量並且在行間{{_txt}}報錯如下:

<code>`Keys starting 

with

with

'_'

are

reserved

`

/<code>

以'_'開頭的鍵被保留

學習'bug':

<code>

data

(){

return

{ $txt:{}, } }, created(){

this

.$txt = {n:

2

}; }, mounted(){ console.log(

this

.$txt) } 我們來對他進行監控 created() {

this

.$txt = { n:

2

}; let n =

2

; Object.defineProperty(

this

.$txt,

"n"

, {

get

() {

return

n; },

set

(

val

) {

return

(n =

val

); } }); }, mounted() {

this

.$txt.n =

3

; console.log(

this

.$txt.n); }/<code>

我們來對他進行監控

<code>created() {
    

this

.$txt = { n:

2

}; let n =

2

; Object.defineProperty(

this

.$txt,

"n"

, {

get

() {

return

n; },

set

(

val

) {

return

(n =

val

); } }); }, mounted() {

this

.$txt.n =

3

; console.log(

this

.$txt.n); }/<code>

這樣就實現了: 數據掛在data上面可以取到, 但是這個數據又沒有vue進行監控, 這樣玩法就多了去了, 是個挺不錯的思維.解釋因為我用'a'接值會導致vue的觀察與3d團隊的觀察衝突, 所以報錯'$a'當然就不衝突了反饋這個技術點我已於3d團隊進行反饋, 希望在文檔中明確, 防止其他同學撓頭.

9: dom: ResizeObserver

bug顯現:在使用可視化團隊開發的圖標組件時發現了問題, 當窗口size變化的時候, 圖標會自動調整自己的佈局寬度, 但是...這個圖標是100%充滿父級的, 或者是flex:1充滿父級的, 當他的父級變化,並沒有出發winodw.onresize的事件的時候, 突變沒有調整自己的寬度.bug起因:只監控了窗口的尺寸變化, 忽略了父級本身的尺寸變化bug解決方案1:我對可以使其父級寬度變化的function加上了一個cb, 這樣就知道父級的每次更改了, 但是這個需要在能影響父級變化的函數里面逐一的加.bug解決方案2: 限谷歌神奇的ResizeObserver, 簡直好用

<code>

<

template

>

<

div

>

<

div

ref

=

"wrap"

class

=

"wrap"

>

<

div

class

=

"box"

>

1

div

>

div

>

div

>

template

>

<

script

>

export

default

{ mounted(){

const

wrap =

this

.$refs.wrap;

const

resizeObserver =

new

ResizeObserver(

(

item

)=>

{

console

.log(

'變化'

, item) }); resizeObserver.observe(wrap) }}

script

>

<

style

>

.wrap

{

border

:

1px

solid red;

width

:

50%

; }

.box

{

border

:

1px

solid black;

margin

:

20px

; }

style

>

/<code>


第一期:前端九條bug分享


分享到:


相關文章: