【工具】前端 debug 的奇技淫巧
為什么要寫這個(gè)文章呢?其實(shí)發(fā)現(xiàn)很多同學(xué)對(duì)一些很簡(jiǎn)單又有效的 debug 手段都不太了解,找 bug 的方式都不是很高效,導(dǎo)致最終 bug 找不到或者走了很多彎路。
Devtools
作為前端開發(fā),chrome 的 devtools 一定不陌生,下面講一講 devtools 里面 debug 的一些思路。
breakpoint
其中斷點(diǎn)是最最經(jīng)常用到的,但很多同學(xué)都只用過默認(rèn)的 breakpoint,其實(shí)還有其他兩種。
breakpoint
當(dāng)代碼執(zhí)行到該行代碼時(shí)暫停
conditional breakpoint
條件斷點(diǎn),當(dāng)表達(dá)式為 true 時(shí)才會(huì)暫停,下圖是當(dāng)變量a === 1時(shí)才暫停。經(jīng)典應(yīng)用場(chǎng)景是當(dāng) bug 是偶現(xiàn)時(shí),你需要知道入?yún)⑹裁吹恼徽?,你可以打一個(gè)你認(rèn)為不正常的條件斷點(diǎn),看看是誰調(diào)用的。PS:值得注意的是,如果你的表達(dá)式報(bào)錯(cuò),那這個(gè)斷點(diǎn)就會(huì)不生效,需要甄別到底是報(bào)錯(cuò)引起的斷點(diǎn)沒進(jìn)入還是真的沒進(jìn)入。
logpoint
日志斷點(diǎn),當(dāng)代碼執(zhí)行到這里時(shí),會(huì)在控制臺(tái)輸出你的表達(dá)式,不會(huì)暫停代碼執(zhí)行,下圖是將 a 輸出到控制臺(tái)的例子。
值得注意的是,當(dāng)你在調(diào)試帶有 sroucemap 的壓縮后的代碼,可能會(huì)產(chǎn)生你看到的變量名和實(shí)際運(yùn)行時(shí)拿到的變量名不一樣,此時(shí)可以在右側(cè) scope 找到你想要的真實(shí)變量名或者在 source 面板 disable 掉 js 的 sourcemap 后再打斷點(diǎn)。
Performance
當(dāng)你做了一些操作,不確定到底執(zhí)行了什么代碼時(shí),可以利用 performance 來捕獲到底什么樣的代碼被執(zhí)行了,結(jié)合你的具體情況,有時(shí)候也會(huì)找到線索,有意想不到的收獲。
是誰動(dòng)了我的代碼
經(jīng)典面試題,如何找到是誰阻止了冒泡,直接在控制臺(tái)輸入下面的代碼即可。經(jīng)常用于尋找我綁定的事件為什么沒有被觸發(fā)。
var tmpStopPropagation = MouseEvent.prototype.stopPropagation;
MouseEvent.prototype.stopPropagation = function(...args) {
console.trace('stopPropagation');
tmpStopPropagation.call(this, ...args);
};
下面這個(gè)例子是找到到底是誰對(duì)容器進(jìn)行了滾動(dòng),比如我們遇到一些頁面跳動(dòng)或者抖動(dòng)的場(chǎng)景,尋找到底是誰滾動(dòng)了容器,當(dāng)然滾動(dòng)還有其他方法會(huì)觸發(fā),比如scrollIntoView,但思路都是一樣的,代理這個(gè)方法即可。
var tmpScrollTop = element.scrollTop;
Object.defineProperty(element, 'scrollTop', {
get: function() {
return tmpScrollTop;
},
set: function(newVal) {
console.trace('scrollTop');
tmpScrollTop = newVal;
}
})
setTimeout
如果我們?cè)谙胍驍帱c(diǎn)的時(shí)候依賴鼠標(biāo)或者鍵盤操作,如果你去 source 面板去點(diǎn)擊暫定,那我的現(xiàn)場(chǎng)就沒有了,那下面的代碼會(huì)幫你解決問題。
setTimeout(() => {debugger;}, 4000);
還有這樣一種 case,比如我期望在我鼠標(biāo)移動(dòng)時(shí)看看某個(gè)變量值是多少,此時(shí)不要再傻傻的在代碼里面添加 console.log,直接運(yùn)行下面的代碼,可以實(shí)時(shí)看到你想要的變量。這個(gè)方法比較像logpoint,不過不需要找源碼去打斷點(diǎn),各有各的應(yīng)用場(chǎng)景。
setTimeout(() => {console.log(yourInstance.getSomeValue());}, 100);
SSR
當(dāng)你想要 debug 某個(gè)頁面上 SSR 渲染的樣式時(shí),可以禁用掉 js 的執(zhí)行,具體操作是打開 devtools 的 source 面板,然后 cmd+p,輸入「>disable javascript」,按回車,然后刷新頁面,你的頁面就是純 SSR 狀態(tài)了。
二分法
這個(gè)是終極 debug 方法,很少會(huì)用到,但也很通俗易懂,有一定應(yīng)用場(chǎng)景。當(dāng)你發(fā)現(xiàn)在某個(gè)版本之后你的代碼出了問題,但又各種找不到思路,我只知道在 A 版本沒問題,B 版本就有問題了,或者代碼突然出了問題,又不知道是依賴了誰出的問題,就可以用這種方法??偟乃悸肪褪恰缚刂谱兞俊梗憧梢栽诖a中批量注釋一些代碼,然后驗(yàn)證問題還有沒有,如果還就的話就繼續(xù)注釋,沒有的話問題就出在被注釋的代碼里,比較像算法中的二分法。
總結(jié)
如何 debug 還有更多的技巧,我這里寫的也只是一部分,如果有其他更好的思路歡迎留言。
