概覽#

斷點(Breakpoint)是 Sources 面板的核心,能讓 JavaScript 在特定時機暫停執行,方便進行檢查。除了直接在程式碼行號上點擊建立斷點,還有非常多種更有效率的建立方式,適合不同情境。

重整頁面不會清除已建立的斷點,這也是斷點的核心機制之一。

對應到 Sources 面板右側子面板,本章會介紹下列幾種斷點:

  • 標記斷點:執行到程式碼特定位置時暫停。
  • 條件式斷點(Conditional Breakpoint):條件成立時才暫停。
  • DOM Breakpoint:特定 DOM 元素發生變化時暫停。
  • XHR Breakpoint:請求網址符合條件時暫停。
  • Event Listener Breakpoint:特定事件被觸發時暫停。
  • Exception 斷點:錯誤產生時暫停。
  • Function 斷點:特定 Function 執行時暫停。

標記斷點#

標記斷點官方稱為 line-of-code,會在該行程式碼執行前暫停。Chrome DevTools 已支援更精細的「特定位置」標記,例如同一行用到 forEachmap 等迭代 Function,可以單獨對某個 callback 下斷點。

建立方式:

  • 開啟 Sources 面板。
  • 打開要中斷的檔案。
  • 點擊行號建立斷點。

點擊行號後,右側會出現多個小箭頭,可在斷點選單中以右鍵選項跳到任一斷點位置。除了一般標記,行號的右鍵選單還能加入:

  • Add conditional breakpoint:執行結果不如預期時才暫停。
  • Add logpoint:相當於插入一條 console.log
  • Never pause here:可以用來跳過程式中的 debugger 關鍵字。

Logpoint#

Logpoint 看起來像 console.log,但有獨特的優勢:

  • 可以快速開關,不需要動到原始碼。
  • 修改後重整頁面仍會保留。
  • 當程式碼來自 Source Map(也就是執行的並非這份原始檔)時,編輯本身不會生效,但 Logpoint 仍可用來注入想觀察的程式碼。

debugger 關鍵字#

在程式碼裡直接寫入 debugger 也能讓 JavaScript 暫停,效果與行號斷點相同:

console.log(1);
console.log("pause");
debugger;
console.log(2);

比起插一堆 console.log,搭配 debugger 的暫停可以拿到完整 Scope、調用堆疊(Call Stack)等資訊,更容易找出問題。

DOM Breakpoint#

當希望某個 DOM 元素被修改時暫停 JavaScript,可以用 DOM Breakpoint。在 Inspect 元素後從右鍵選單的 Break on 看到三種類型:

  • Subtree modifications:節點底下的子節點有新增或刪除。
  • Attribute modifications:節點本身的 attribute 有新增、刪除、修改。
  • Node removal:該節點被移除,DOM Breakpoint 也會一併消失。

當某個元素的變化來源不明(例如莫名其妙改了顏色),用 DOM Breakpoint 可以直接定位到修改它的程式碼。

XHR Breakpoint#

Sources 面板右側選單的 XHR/Fetch Breakpoints 可以新增 URL pattern 或攔截所有請求。實務上的好處:

  • 開發時各種請求齊發,能快速定位某個 API 是哪段程式碼發出。
  • 暫停後續請求,避免後續日誌洗掉現場。

Event Listener Breakpoint#

展開 Event Listener Breakpoints 後可以選擇事件分類或單一事件。要特別注意的是它的暫停時機是在事件觸發後、Listener 執行前。

這是作者最推薦的一種斷點。網頁許多行為都靠事件觸發,能快速找到行為對應的程式碼,也能在調樣式時做到「JavaScript 版的狀態鎖定」。

例如想調整由 mouseentermouseleave 控制的 Hover 樣式,但點 DevTools 又會觸發 Blur,這種第三方套件常見的情境特別頭痛。流程:

  • 勾選 Mouse > mousedown
  • 展開選單,點擊選項觸發已註冊的 mouseenter listener。
  • 順利停在 mousedown Event handler 第一行,選單不會關閉,可以從容調整 CSS。

Exception 斷點#

點擊右上方的八邊形暫停標誌,可以在錯誤產生時暫停。預設只攔未捕捉的錯誤,需要勾選 Pause on caught exceptions 才會包含 try-catch 中被捕捉的錯誤。

Promise 即使有 catch,reject 仍會觸發 Exception 斷點。

開啟後測試網頁能讓錯誤一發生就停在「犯罪現場」,方便檢查是否有預期外的錯誤。

Function 斷點#

Console 面板的 debug 工具相當於在某個 Function 第一行插入 debugger

function a() {
  console.log(1);
}
// 在 Console 中
debug(a);

效果等同於:

function a() {
  debugger;
  console.log(1);
}

不過 debug 建立的斷點不會出現在 Sources 面板的斷點列表,只能透過 undebug 解除。

小結#

合理組合上述斷點幾乎可以涵蓋所有 Debug 情境。除了事先設斷點外,也別忘了還有手動暫停:直接按 F8 就會立即暫停 JavaScript 執行。

下一章會接著介紹暫停之後,如何逐步執行 JavaScript 來繼續追查問題。

原文出處#