前端除錯的最佳實踐
一、背景
作為前端工程師,無論是開發還是線上環境,瀏覽器或是 node
,移動端或者 PC
端,經常會遇到一些 bug
,那麼如何快速定位和解決問題呢,筆者準備了一份前端除錯指南供大家參考。
「文章大綱」:

除錯本身可以分為兩個過程, 「定位問題」 和 「解決問題」 。而更重要的顯然是如何快速的定位問題。本文將集中討論如何 「快速發現」 並 「除錯問題」 ,至於如何解決問題,那就是開發本身的事情,無法一概而論了。
二、除錯工具方法
2.1 Chrome DevTools 的使用
Chrome 的 DevTools 是最常用的除錯工具,下面主要介紹下 「Elements」 、 「Console」 和 「Source」 三個面板的使用。
2.1.1 Elements
Elements 面板會顯示目前網頁中的 DOM、CSS 狀態,且可以修改頁面上的 DOM 和 CSS,即時看到結果,省去了在編輯器修改、儲存、瀏覽器檢視結果的流程。
Elements 主要可以分為 DOM 結構以及元素(Element)內容兩個子面板,下面主要介紹一下 Elements DOM
$n
開啟 Elements 面板時,標記的元素後方總會有個
== $0

選中一個元素後再到 Console 面板輸入 $0
,會發現剛剛選中的元素出現在 Console 中,如果再多點幾個元素,還可以用 $1
、 $2
、 $3
、 $4
(到此為止)來拿到前幾次選到的元素。
另外在 Console 中對元素按下右鍵,選擇 Reveal in Elements Panel
可以跳到該元素在 Elements 面板中的位置,對 Elements 面板的元素按下右鍵則有 Scroll to view
可以把視野滾到能看見元素的地方。
想要在 Console 面板中用 JavaScript 操作元素時, $0
就非常方便,另外也可以搭配 console.dir($0)
來觀察元素的各個屬性,如果在 Console 直接輸入 $0
或是 console.log($0)
只會顯示元素自身。

inspect
有時候一些 dom 節點會巢狀很深,導致我們很難利用 Element 面板 html 程式碼來找到對應的節點。 inspect(dom元素)
可以讓我們快速跳轉到對應的 dom 節點的 html 程式碼上。
eg:在 console 輸入 inspect($('#app'))
,回車後便可以跳轉到#app 節點的 html,進行審查元素
2.1.2 Console
Console 面板作為 shell 提示視窗用來和頁面文件以及 DevTools 進行互動
console 物件
前端說起除錯,最常用的肯定就是 console.log
方法,但是 console 是一個物件,上面還有很方便的方法。
console.table()
可用於列印 obj/arr 成表格

console.trace()
可用於 debugger 堆疊除錯,方便檢視程式碼的執行邏輯,也可以幫助我們看一些庫的原始碼

console.count
會印出這個標籤被執行了幾次,預設值是 default
,可以用在快速的計數。
console.countReset
與 count
配套,用來重置,可用在計算單次行為的觸發的計數。
console.group() / console.groupEnd();
為了在一大堆混亂的訊息中一眼看到自己的 log, 通常會這樣做
console.log("----start-----");
console.log(object);
console.log("---end---");
雖然 ---
是很顯眼沒錯,但其實有更好的做法,用 console.group
可以自訂 Message group 的標籤也可以多層巢狀,並用 console.groupEnd
來關閉 Group
console.log("iteration");
for (var firstLevel = 0; firstLevel < 2; firstLevel++) {
console.group("First level: ", firstLevel);
for (var secondLevel = 0; secondLevel < 2; secondLevel++) {
console.group("Second level: ", secondLevel);
for (var thirdLevel = 0; thirdLevel < 2; thirdLevel++) {
console.log("This is third level number: ", thirdLevel);
}
console.groupEnd();
}
console.groupEnd();
}

$$(select)方法
$(select)
拿到的是 NodeList(偽陣列),而 $$(select)
拿到的則是一個純正的陣列,方便我們在控制檯上除錯 API,只有在 devtools 下列印才能使用

2.1.3 Source
Sources
面板可以檢視瀏覽器頁面中的原始檔( html/js/img/css
等),點選面板下方的 {}
大括號可以將程式碼轉成可讀格式,同時可給 js
檔案新增上斷點。 Sources
下的 Snippets
可以新增檔案片段,可在瀏覽器中執行
Breakpoints
「debugger 語句」
在程式碼中加上 debugger
語句,是僅次於 console.log
的常用除錯方式,在需要的地方進行新增斷點
chrome devtool breakpoint 下面列舉一些平常使用較多的斷點方式
-
普通斷點:在想斷住的那一行左側單擊一下就可以新增一個斷點,執行到該處就會斷住。
image-20220104161116371 -
條件斷點:右鍵單擊程式碼所在的行左側,會出現一個下拉框,可以新增一個條件斷點。輸入條件表示式,當執行到這一行程式碼並且表示式的值為真時就會斷住。

-
DOM 斷點:在 Chrome Devtools 的 Elements 面板的對應元素上右鍵,選擇 break on,可以新增一個 dom 斷點,也就是當子樹有變動、屬性有變動、節點移除這三種情況的時候會斷住。可以用來除錯導致 dom 變化的程式碼。

-
Event Listeners 打斷點:在 Chrome Devtools 的 Elements 面板上找到你想排查的 dom 節點,右側面板 Event Listeners 中會有當前階節點,可以當前節點打斷點除錯。
image-20220104161916972 -
異常斷點:在 Debugger 面板勾選 Uncaught Exceptions 和 Caught Exceptions 可以新增異常斷點,在丟擲異常未被捕獲或者被捕獲時斷住。用來除錯一些發生異常的程式碼時很有用。
-
Event Listener 斷點:在 Chrome Devtools 的 Sources 面板還可以新增 Event Listener 的斷點,指定當發生什麼事件時斷住,可以用來除錯事件相關程式碼。比如拖拽事件、媒體事件斷點

-
Function 在 Console 面板中可以用
debug
相當於在該 function 的第一行插入debugger
:
function a() {
console.log(1);
}
// 在Console中輸入
debug(a);
a();
// 相當於
function a() {
debugger;
console.log(1);
}
// 使用 undebug 解除
BlackBox
“BlackBox Script”可以在除錯中忽略某些指令碼(此處的 BlackBox 為動詞),在 Call Stack 堆疊中會將該指令碼隱藏,單步除錯時也不會步入指令碼中的任何函式。如果確認第三方庫沒有 bug,就可以 BlackBox 整個第三方庫的 js 指令碼,在除錯中跳過這些程式碼的執行。
三種新增 BlackBox 的方法:
-
在原始碼窗格右鍵,選擇"BlackBox Script"
-
在 Call Stack 中右鍵某一幀,選擇"BlackBox Script"
-
在設定中的 Blackboxing 面板新增 「正則表示式」 匹配 「檔名」
Workspace
chrome 中 「使用本地 sourceMap 除錯」
第一步:開啟 Filesystem add folder to workspace,把包含 sourceMap 的目錄新增進去

第二步:開啟指定的混淆程式碼

第三步:右鍵 -> 選擇【Add source map】
第四步:拷貝 Filesystem 中的 sourceMap 地址。
在 chrome 中修改程式碼並除錯
chrome devTools 提供了 local overrides 能力,首先,開啟 sources 下的 overrides 面板;
然後,點選【select folder for overrides】選擇修改後的檔案儲存地址;

再然後,點選頂部的授權,確認同意;
最後,找到入口檔案,然後右鍵選擇 Save for overrides
(一定要是原件,formatted 後的版本不行),

然後找到儲存的檔案進行修改,重新重新整理頁面後,修改後的程式碼就可以被執行了。
2.2 nodejs 除錯
Nodejs 使用 Chrome DevTools 除錯 --inspect-brk
下面以除錯 webpack 原始碼為例:
node --inspect --inspect-brk node_modules/webpack/bin/webpack.js --env.production --config webpack-common.js
執行 bin 中相應 「啟動檔案」 webpack.js 開啟 chrome 的開發者工具頁面,如果看到 node 的 「綠色圖示」 ,點選就可進入除錯。

2.3 移動端除錯 VConsole 與 eruda
whistle 配合 VConsole 或者 eruda,可以在任何環境下開啟除錯模式,在 whistle 中 規則中配置相應域名下進行除錯,以 m.zhuanzhuan.com 域名為例
m.zhuanzhuan.com jsAppend://{eruda.js} jsAppend://{erudaInit.js}
下載 eruda.js,把 eruda.js 和 erudaInit.js 配置在 values 中


這樣就會在移動端開啟除錯 eruda 模式了。
2.4 微信 WebView 除錯
微信除錯網頁,正常來說你可以使用微信開發者工具 [1]
進行除錯。它本質上和 chrome://inspect
方法類似,只是它為線上的微信包提供了 debug 模式,並將操作簡單化。具體的使用方法可以參考官方文件:https://x5.tencent.com/tbs/guide/debug/season1.html
2.5 Android Chrome 真機除錯
如果你需要除錯的 Android 手機版本 >= 4.4,則推薦使用 chrome://inspect
的方式進行除錯,它能為 WebView 帶來原生的開發者工具,可以方便的對程式碼進行斷點除錯。該方法需要滿足以下三個條件才能使用:
-
Android 4.4+
-
手機上開啟允許 USB 連線裝置進行除錯
-
客戶端開啟 WebView debug 模式
//開啟 webview 的 debug 模式
webview.setWebContentsDebuggingEnabled(true);
當滿足以上要求之後,訪問 chrome://inspect
,頁面將顯示您的裝置上已啟用除錯的 WebView 列表。要開始除錯,請點選您想要除錯的 WebView 下方的 inspect。像使用遠端瀏覽器標籤一樣使用開發者工具。
2.6 iOS Safari 真機除錯
如果你手機上安裝的是 DEBUG 版應用,那麼推薦使用 Safari 來除錯,它能為 WebView 帶來原生的開發者工具,可以方便的對程式碼進行斷點除錯。該方法需要滿足以下三個條件才能使用:
-
Mac: Safari -> 偏好設定 -> 高階 -> 在選單欄中顯示“開發”選單勾選
-
iOS: 設定 -> Safari -> 高階 -> Web 檢查器開啟
-
最重要的是 App 必須開啟 DEBUG 模式
由於 iOS 有簽名校驗機制,真機正式包不允許 Safari Debug,所以安裝在真機上的包必須是測試簽名打的包。需要聯絡客戶端將我們 iOS 裝置的 ID 寫入到可信任裝置列表中,然後使用 iTunes 安裝客戶端提供的測試包即可。當滿足以上要求後,就可以在 Safari -> 開發中看到自己的裝置以及 WebView 中網頁,點選後即可開啟對應頁面的 Inspector,可以用來進行斷點除錯。
2.7 weinre 除錯
當系統版本或者未開啟 debug 模式導致上面的方法不可用時,可以考慮使用 weinre [2] 。weinre 通過在頁面中插入一段指令碼,將頁面的所有行為傳送到服務上。首先我們需要安裝並啟動服務:
npm install -g weinre
weinre --httpPort 8000
訪問 http://localhost:8000
按照頁面提示將 debug 指令碼插入到頁面中。訪問頁面後就會發現 winere 頁面中出現了對應的請求記錄,點選該記錄即可跳到如下頁面。可以看到這個就是一個網頁版的開發者工具,可以方便的檢視網路請求,控制檯執行程式碼以及樣式修改等。
三、除錯方法彙總
方式 | 優點 | 缺點 | 推薦場景 |
---|---|---|---|
移動端網路代理+whistle 本地代理 | 1、開發環境方便 | 1、無法斷點除錯 | 1、推薦開發環境使用 |
whistle 外部工具注入(vConsole.js 或 Eruda.js) | 1、方便 | 2、無法斷點除錯 | 1、推薦任何環境除錯 |
Android 真機除錯 | 1、最接近真實環境,可以斷點除錯 |
1、條件苛刻麻煩; 2、僅限 Android; 3、不夠方便 |
1、實在找不到問題的保底手段 |
iOS Safari 真機除錯 | 1、最接近真實環境,可以斷點除錯 |
1、條件苛刻麻煩; 2、僅限 ios; 3、不夠方便 |
1、實在找不到問題的保底手段 |
微信開發者工具除錯 | 1、可以 pc 一樣方便的斷點除錯 |
1、僅限微信; 2、要提前將自己的賬號加入到開發者賬號中 |
1、任何需要使用到微信的場景 |
weinre(web inspector remote) |
1、在 whistle 內有繼承,比較方便; 2、方便除錯樣式,選中即可得 |
1、無法斷點除錯 | 1、任何需要除錯樣式的場景 |
四、除錯一般步驟
當出現異常時,按照這個基本邏輯排查,一般可以快速定位問題。
4.1 檢查控制檯是否報錯
可以快速確定頁面不符合預期的原因
-
是何種錯誤
-
當前頁面是否需要請求獲取資料
4.2 是何種錯誤
-
安全錯誤:與後端協商解決
-
SyntaxError/ReferenceError/TypeError :編譯階段一般不會放過太低階的書寫錯誤,可以認為這類錯誤都是寫錯了 ,一般很容易發現,找到錯誤堆疊進行解決
-
資料不符合預期引起的錯誤(TypeError 等):訪問不存在的屬性得到了
undefined/null/NaN
等值之後,會引發後續的異常。要先從檢查資料入手。
4.3 當前頁面是否需要請求獲取資料
網路請求是不穩定因素之一,可能會帶來難以預料的複雜情況,出現問題的時候檢查網路請求和資料的優先順序很高。
4.4. 網路請求是否成功傳送
檢查開發者工具 Network/網路面板,檢視需要獲取資料的介面是否成功獲取到資料。
取不到資料的原因有兩類,一類是責任在前端,一類是後端。主要通過請求提交的內容是否合法,介面返回內容是否符合預期兩個方面判斷。
檢視的關鍵點:
-
方法是否正確
-
URL 是否正確
-
跨域
-
請求的 Content-Type 是符合要求
-
請求體格式是否符合要求(JSON/Form)
-
是否攜帶了身份資訊
合法請求沒有得到預期返回,就找後端解決,請求與預期不符就是程式碼寫錯了,到錯誤地方檢視程式碼。
-
500 等不該出現的異常:500 大概可能是後端問題
-
404 URL 寫錯
-
許可權問題:檢查請求報文攜帶的身份資訊
4.5 定位到程式碼應當執行的位置(大概即可)
如果是控制檯有錯誤資訊的,利用 sourcemap 可以快速定位到問題出在哪一行。如果沒有報錯資訊,就需要憑藉當前頁面的狀態自己判斷出問題的區域,按照程式碼執行的順序排查。這一步可以利用的手段比較多,情況也更復雜,需要具體分析。
檢視程式碼執行狀態:
-
按照預期執行順序檢查程式碼
-
檢查渲染需要的資料是否與預期相同
4.6 按照預期執行順序檢查程式碼
通過斷點、日誌等手段判斷程式有沒有按照自己想要的順序執行,簡單來說就是排查。
4.7 檢查渲染需要的資料是否與預期相同
檢查執行過程中每一步的資料變化,是否與預期的相同。
4.8 異常程式碼一般分析方法
-
「程式碼註釋法」利用二分法思想逐行去註釋程式碼,直到定位問題
-
「類庫異常,相容問題」 這種場景也會經常遇到,我們需要用可以除錯頁面異常的方式,如
Safari
,Whistle
,vConsole
檢視異常日誌,從而迅速定位類庫位置,從而找尋替換或是相容方案。 -
「try catch」 如果你的專案沒有異常監控,那麼在可疑的程式碼片段中去
Try Catch
吧。 -
「ES6 語法相容」 一般我們都會通過
Babel
來編譯ES6
,但是額外的第三方類庫如果有不相容的語法,低版本的移動裝置就會異常。所以,先用上文講述的除錯方法,確定異常,然後去增加 polyfill 來相容吧
五、總結
寫到這裡整篇文章的除錯方法就結束了。也許有很多不到位的地方,專業用詞不嚴謹的地方,希望讀者和我一起交流。非常樂意我的除錯總結給予前端人受用。
Reference
微信開發者工具: https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html
weinre: http://people.apache.org/~pmuellr/weinre/
- UMI3原始碼解析系列之外掛化架構核心
- umi3原始碼解析之核心Service類初始化
- umi3原始碼解析之核心Service類初始化
- 學會Sequelize,讓你操作資料更絲滑
- 學會Sequelize,讓你操作資料更絲滑
- 多專案整合下的工程腳手架配置方案
- 教你如何實現一個完美的移動端瀑布流元件(附原始碼)
- 如何實現馬良的標註功能
- 如何實現馬良的標註功能
- 如何成為一個優秀的複製貼上工程師
- [薦]Apache ShardingSphere在轉轉億級交易系統落地實踐
- 搭建場景下的頁面編譯提速方案探索
- 前端除錯的最佳實踐
- Gitlab CI持續整合可以這樣用
- 複雜場景下喚起App實踐
- 奇葩說框架之React的渲染流程解析
- 奇葩說框架之React渲染流程解析
- 奇葩說框架之Vue3渲染系統
- 奇葩說框架之React編譯原理
- 奇葩說框架之React編譯原理