前言
工欲善其事,必先利其器。最近在寫程式碼的時候越發覺得不是程式碼有多難,而是當程式碼出了問題該如何除錯,如何追溯本源,這才是最難的。
響應這個要求,我決定寫一個關於除錯實戰系列。本來不打算寫這個基礎篇章,為了整個的完整性。(不喜勿噴)
打算出三個篇章
3.急速 debug 實戰三 (Node - webpack外掛,babel外掛,vue原始碼篇)
所以示例在以下環境通過。
作業系統: MacOS 10.13.4
Chrome: 版本 72.0.3626.81(正式版本) (64 位)
斷點除錯JS
可能很多人現在還比較頻繁的用著 console.log
的方式除錯著程式碼,這種方式不說他絕對的不好,只是相比之下斷點有以下兩個優勢:
-
使用
console.log()
,您需要手動開啟原始碼,查詢相關程式碼,插入console.log()
語句,然後重新載入此頁面,才能在控制檯中看到這些訊息。 使用斷點,無需瞭解程式碼結構即可暫停相關程式碼。 -
在
console.log()
語句中,您需要明確指定要檢查的每個值。 使用斷點,DevTools 會在暫停時及時顯示所有變數值。 有時在您不知道的情況下,有些變數會影響您的程式碼。
問題
1.開啟: yifenghua.win/example/deb…
2.在 Number 1
文字框中輸入 5。
3.在 Number 2
文字框中輸入 1。
4.點選 Add Number 1 and Number 2
。 按鈕下方的標籤顯示5 + 1 = 51
。 結果應為 6。 這就是我們需要修正的問題。
介面
第 1 步:重現錯誤
1.通過按Command+Option+I (Mac)
或 Control+Shift+I(Windows、Linux)
,開啟 DevTools。 此快捷方式可開啟 Console
皮膚。
2.點選 Sources 標籤。
第 3 步:使用斷點暫停程式碼
如果退一步思考應用的運作方式,您可以根據經驗推測出,使用與 Add Number 1 and Number 2 按鈕關聯的 click 事件偵聽器時計算的和不正確 (5 + 1 = 51)
。 因此,您可能需要在 click
偵聽器執行時暫停程式碼。 Event Listener Breakpoints 可讓您完成此任務:
- 在 JavaScript Debugging 窗格中,點選 Event Listener Breakpoints 以展開該部分。 DevTools 會顯示 Animation 和 Clipboard 等可展開的事件類別列表。
- 在 Mouse 事件類別旁,點選 Expand Expand 圖示。 DevTools 會顯示 click 和 mousedown 等滑鼠事件列表。 每個事件旁都有一個核取方塊。
- 勾選 click 核取方塊。 DevTools 現在經過設定可以在任何 click 事件偵聽器執行時自動暫停。
- 返回至演示頁面,再次點選 Add Number 1 and Number 2。 DevTools 會暫停演示並在 Sources 皮膚中突出顯示一行程式碼。 DevTools 應在此程式碼行暫停:
function onClick() {
複製程式碼
如果是在其他程式碼行暫停,請按 Resume Script Execution 繼續執行指令碼, 直到在正確的程式碼行暫停為止。
單步除錯程式碼
一個常見的錯誤原因是指令碼執行順序有誤。 可以通過單步除錯程式碼一次一行地檢查程式碼執行情況,準確找到執行順序異常之處。 立即嘗試:
在 DevTools 的 Sources 皮膚上,點選 Step into next function call 單步執行時進入下一個函式呼叫,以便一次一行地單步除錯 onClick() 函式的執行。 DevTools 突出顯示下面這行程式碼:
if (inputsAreEmpty()) {
複製程式碼
點選 Step over next function call 單步執行時越過下一個函式呼叫。 DevTools 執行但不進入 inputsAreEmpty()
。 請注意 DevTools 是如何跳過幾行程式碼的。 這是因為 inputsAreEmpty()
求值結果為 false,所以 if
語句的程式碼塊未執行。
這就是單步除錯程式碼的基本思路。 如果看一下 get-started.js
中的程式碼,您會發現錯誤多半出在 updateLabel()
函式的某處。 您可以使用另一種斷點來暫停較接近極可能出錯位置的程式碼,而不是單步除錯每一行程式碼。
設定程式碼行斷點
程式碼行斷點是最常見的斷點型別。 如果您想在執行到某一行程式碼時暫停,請使用程式碼行斷點:
看一下 updateLabel()
中的最後一行程式碼:
label.textContent = addend1 + ' + ' + addend2 + ' = ' + sum;
複製程式碼
在這行程式碼的左側,您可以看到這行程式碼的行號是 32。 點選 32。 DevTools 會在 32 上方放置一個藍色圖示。 這意味著這行程式碼上有一個程式碼行斷點。 DevTools 現在始終會在執行此行程式碼之前暫停。
點選 Resume script execution 繼續執行指令碼 。 指令碼將繼續執行,直到第 32 行。 在第 29 行、第 30 行和第 31 行上,DevTools 會在各行分號右側輸出 addend1
、addend2
和 sum
的值。
檢查變數值
addend1
、addend2
和 sum
的值疑似有問題。 這些值位於引號中,這意味著它們是字串。 這個假設有助於說明錯誤的原因。 現在可以收集更多資訊。 DevTools 可提供許多用於檢查變數值的工具。
方法 1:Scope 窗格 在某程式碼行暫停時,Scope 窗格會顯示當前定義的區域性和全域性變數,以及各變數值。 其中還會顯示閉包變數(如果適用)。 雙擊變數值可進行編輯。 如果不在任何程式碼行暫停,則 Scope 窗格為空。
方法 2:監視表示式 Watch Expressions 標籤可讓您監視變數值隨時間變化的情況。 顧名思義,監視表示式不僅限於監視變數。 您可以將任何有效的 JavaScript 表示式儲存在監視表示式中。 立即嘗試:
點選 Watch 標籤。
點選 Add Expression 新增表示式。
輸入 typeof sum
。
按 Enter
鍵。 DevTools 會顯示 typeof sum: "string"
。 冒號右側的值就是監視表示式的結果。
正如猜想,sum 的求值結果本應是數字,而實際結果卻是字串。 現在已確定這就是錯誤的原因。
方法 3:控制檯
除了檢視 console.log()
訊息以外,您還可以使用控制檯對任意 JavaScript 語句求值。 對於除錯,您可以使用控制檯測試錯誤的潛在解決方法。 立即嘗試:
如果您尚未開啟 Console 抽屜式導航欄,請按 Escape 將其開啟。 該導航欄將在 DevTools 視窗底部開啟。
在 Console 中,輸入 parseInt(addend1) + parseInt(addend2)
。 此語句有效,因為您會在特定程式碼行暫停,其中 addend1
和 addend2
在範圍內。
按 Enter
鍵。 DevTools 對語句求值並列印輸出 6
,即您預計演示頁面會產生的結果。
應用修正方法
您已找到修正錯誤的方法。 接下來就是嘗試通過編輯程式碼並重新執行演示來使用修正方法。 您不必離開 DevTools 就能應用修正。 您可以直接在 DevTools UI 內編輯 JavaScript 程式碼。 立即嘗試:
- 點選 Resume script execution 繼續執行指令碼。
- 在 Code Editor 中,將第 31 行
var sum = addend1 + addend2
替換為var sum = parseInt(addend1) + parseInt(addend2)
。 3.按Command+S (Mac)
或Control+S(Windows、Linux)
以儲存更改。 - 點選 Deactivate breakpoints 取消啟用斷點。 其將變為藍色,表示處於活動狀態。 在完成此設定後,DevTools 會忽略您已設定的任何斷點。
- 嘗試使用不同的值執行演示。 現在演示可以正確計算。
各類斷點使用概覽
斷點型別 | 情況 |
---|---|
程式碼行 | 在確切的程式碼區域中。 |
條件程式碼行 | 在確切的程式碼區域中,且僅當其他一些條件成立時。 |
DOM | 在更改或移除特定 DOM 節點或其子級的程式碼中。 |
XHR | 當 XHR 網址包含字串模式時。 |
事件偵聽器 | 在觸發 click 等事件後執行的程式碼中。 |
異常 | 在引發已捕獲或未捕獲異常的程式碼行中。 |
函式 | 任何時候呼叫特定函式時。 |
程式碼行斷點
在知道需要調查的確切程式碼區域時,可以使用程式碼行斷點。 DevTools 始終會在執行此程式碼行之前暫停。
在 DevTools 中設定程式碼行斷點:
- 點選 Sources 標籤。
- 開啟包含您想要中斷的程式碼行的檔案。
- 轉至程式碼行。
- 程式碼行的左側是行號列。 點選行號列。 行號列頂部將顯示一個藍色圖示。
程式碼中的程式碼行斷點
在程式碼中呼叫 debugger
可在該行暫停。 此操作相當於使用程式碼行斷點,只是此斷點是在程式碼中設定,而不是在 DevTools 介面中設定。
console.log('a');
console.log('b');
debugger;
console.log('c');
複製程式碼
條件程式碼行斷點
如果知道需要調查的確切程式碼區域,但只想在其他一些條件成立時進行暫停,則可使用條件程式碼行斷點。
若要設定條件程式碼行斷點:
- 點選 Sources 標籤。
- 開啟包含您想要中斷的程式碼行的檔案。
- 轉至程式碼行。
- 程式碼行的左側是行號列。 右鍵點選行號列。
- 選擇 Add conditional breakpoint。 程式碼行下方將顯示一個對話方塊。
- 在對話方塊中輸入條件。
- 按 Enter 鍵啟用斷點。 行號列頂部將顯示一個橙色圖示。
管理程式碼行斷點
使用 Breakpoints 窗格可以從單個位置停用或移除程式碼行斷點。
顯示兩個程式碼行斷點的 Breakpoints 窗格:一個程式碼行斷點位於 get-started.js
第 15 行,另一個位於
第 32 行
- 勾選條目旁的核取方塊可以停用相應的斷點。
- 右鍵點選條目可以移除相應的斷點。
- 右鍵點選 Breakpoints 窗格中的任意位置可以取消啟用所有斷點、停用所有斷點,或移除所有斷點。 停用所有斷點相當於取消選中每個斷點。 取消啟用所有斷點可讓 DevTools 忽略所有程式碼行斷點,但同時會繼續保持其啟用狀態,以使這些斷點的狀態與取消啟用之前相同。
DOM 更改斷點
如果想要暫停更改 DOM 節點或其子級的程式碼,可以使用 DOM 更改斷點。
若要設定 DOM 更改斷點:
- 點選 Elements 標籤。
- 轉至要設定斷點的元素。
- 右鍵點選此元素。
- 將滑鼠指標懸停在 Break on 上,然後選擇 Subtree modifications、Attribute modifications 或 Node removal。
DOM 更改斷點的型別
-
Subtree modifications: 在移除或新增當前所選節點的子級,或更改子級內容時觸發這類斷點。 在子級節點屬性發生變化或對當前所選節點進行任何更改時不會觸發這類斷點。
-
Attributes modifications:在當前所選節點上新增或移除屬性,或屬性值發生變化時觸發這類斷點。
-
Node Removal:在移除當前選定的節點時會觸發。
XHR/Fetch 斷點
如果想在 XHR
的請求網址包含指定字串時中斷,可以使用 XHR 斷點。 DevTools 會在
XHR 呼叫 send()
的程式碼行暫停。
注:此功能還可用於 Fetch 請求。
例如,在您發現您的頁面請求的是錯誤網址,並且您想要快速找到導致錯誤請求的 AJAX 或 Fetch 原始碼時,這類斷點很有用。
若要設定 XHR 斷點:
- 點選 Sources 標籤。
- 展開 XHR Breakpoints 窗格。
- 點選 Add breakpoint。
- 輸入要對其設定斷點的字串。 DevTools 會在 XHR 的請求網址的任意位置顯示此字串時暫停。
- 按 Enter 鍵以確認。
事件偵聽器斷點
如果想要暫停觸發事件後執行的事件偵聽器程式碼,可以使用事件偵聽器斷點。
您可以選擇 click
等特定事件或所有滑鼠事件等事件類別。
- 點選 Sources 標籤。
- 展開 Event Listener Breakpoints 窗格。 DevTools 會顯示 Animation 等事件類別列表。
- 勾選這些類別之一以在觸發該類別的任何事件時暫停,或者展開類別並勾選特定事件。
異常斷點
如果想要在引發已捕獲或未捕獲異常的程式碼行暫停,可以使用異常斷點。
- 點選 Sources 標籤。
- 點選 Pause on exceptions 。 啟用後,此按鈕變為藍色。
- (可選)如果除未捕獲異常以外,還想在引發已捕獲異常時暫停,則勾選 Pause On Caught Exceptions 核取方塊。
函式斷點
如果想要在呼叫特定函式時暫停,可以呼叫 debug(functionName)
,其中 functionName
是要除錯的函式。
您可以將 debug()
插入您的程式碼(如 console.log()
語句),也可以從 DevTools 控制檯中進行呼叫。
debug()
相當於在第一行函式中設定程式碼行斷點。
function sum(a, b) {
let result = a + b; // DevTools pauses on this line.
return result;
}
debug(sum); // Pass the function object, not a string.
sum();
複製程式碼
確保目標函式在範圍內
如果想要除錯的函式不在範圍內,DevTools 會引發 ReferenceError
。
(function () {
function hey() {
console.log('hey');
}
function yo() {
console.log('yo');
}
debug(yo); // This works.
yo();
})();
debug(hey); // This doesn't work. hey() is out of scope.
複製程式碼
如果是從 DevTools 控制檯中呼叫 debug()
,則很難確保目標函式在範圍內。
下面介紹一個策略:
- 在函式在範圍內時設定程式碼行斷點。
- 觸發此斷點。
- 當程式碼仍在程式碼行斷點位置暫停時,即於 DevTools 控制檯中呼叫
debug()
。
額外的除錯技巧
我們在除錯一些 hover 屬性的時候,往往想要調整 hover 後顯示的元素,但是每當我們移到觀察此元素的時候就會消失。這使得除錯非常不方便。下面就提供幾種場景,分別來給出除錯的方案。
demo: yifenghua.win/example/deb…
Hover
單純的 hover 屬性我們只需要找到觸發的元素。在這裡是我們 button。所以我們在 elements 中找到我們對應的 hover 元素。右鍵-> force state -> :hover
Mouse inner
如果是通過 mouse (滑鼠事件來觸發的)並且觸發元素是寫在觸發元素內的情況。可以通過在當前觸發元素。右鍵 -> Break on -> subtree modifications。 然後再次觸發,選擇跳過斷點。就可以使得元素出現。
Mouse outer
如果是通過 mouse (滑鼠事件來觸發的)並且觸發元素是寫在觸發元素外的情況。可以通過斷點觸發來阻斷。(此方法也相容 mouser inner 的情況)。當觸發元素的時候按下 F8 (Windwos)
/ command + \ (Mac)
參考文獻
developers.google.com/web/tools/c…
更多請關注
友情連結: huayifeng.top/