iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 14
1
Modern Web

你所不知道的各種前端 Debug 技巧系列 第 14

[Day 14] Sources - JavaScript Debugging

使用 JavaScript Debugger 的精髓除了斷點、逐步執行外,還有各種列表顯示 JavaScript 目前的執行狀態,以及一些關於 Debugger 的設定。

閱讀本篇文章時建議搭配 Demo 頁面 Sources - JavaScript Debugging,效果更佳。

狀態列表

Watch

執行程式碼的過程中,若需要不斷查看某個變數的值,可以在 Watch 列表中新增一條 Expression。

加入後每次暫停或逐步執行都會重新執行 Watch 中的 Expression,另外也可以手動按下右方的 Refresh watch expressions 圖示來刷新 Expression。

需要注意的就是 Expression 可能會觸發副作用,關於 Watch 的副作用在 Console - Run JavaScript 中的 Live expression 也有提及,當 Expression 為 Function 時有副作用較易察覺,但若是藏在物件的 Getter 中就很可能被忽略了。

 

Scope

Scope 列表中會顯示目前各個 Scope 可取得的變數值,JavaScript Debugger 中的 Scope 可以簡單歸類為以下幾種:

  • Local – 目前所在 Function scope 宣告的變數
  • Block – 同一個 Block scope(大括弧)宣告的變數
  • Closure – 目前所在 Function 可見的外部 Function scope 變數
  • Script – Global scope 宣告的變數(constlet
  • Global – 可透過 window.x 取得的屬性(var

以下列程式碼為例子,假設目前停在 console.log,試著猜猜看 a、b、c、d、e 在 Scope 列表中會分別被歸類於哪一種 Scope:

var a = 'a';
const b = 'b';
function outer() {
  const c = 'c';
  function inner() {
    const d = 'd';
    if (true) {
      const e = 'e';
      console.log(a, b, c, d, e); // 斷點
    }
  }
  inner();
}
outer();

 
答案在下方,可以在 Demo 頁面看看實際的執行結果,是否和自己的想法一致呢?注意 functionvar 的宣告是屬於 Function scope,更詳細的說明可以參考 MDN 關於 FunctionsBlock 的文件。

注意變數可能同時屬於多種 Scope,在 Sources 面板的 Scope 列表中會自動歸類到其中一種。
答案是 Global, Script, Closure, Local, Block

 

修改變數

雙擊變數可以修改變數值,比較特別的是 Function 執行到最後一行的時候 Local scope 會出現 Return value,可以修改 Return value 的值,甚至 Function 本身的程式碼也可以修改。

另外右鍵點擊 Scope 列表內的 Function 會多一個 Show function definition 選項,可以跳至該 Function 宣告的位置。

 

Call stack

每多執行一層 Function,Call stack 就會加入一層 Function,以下方程式碼為例,若在 C 行加入斷點,執行 outer 後會看到 Call stack 裡面出現 helloworld

function hello() {
  let message = 'Hello'; // A
  function world() {
    message = message + ' World'; // C 斷點
    console.log(message);
  }
  inner(); // B
}

 

切換

Call stack 內的藍色箭頭會指向顯示目前正在觀察的 Function,點擊其他 Function 如 hello 可以看到進入 world 前的狀態:

重新執行

右鍵點擊任意一層可以看到 Restart frame 選項,點擊後會跳至該 Function 的第一行,以下方程式碼為例子,假設目前停在 C 行,點擊 Step 執行 C 行後,再點擊 Restart Frame 就會跳至 C 行之前。

Hello 後面加了兩次 World

 

Console

暫停時可以在 Console 內執行任意 JavaScript,例如修改變數、Console.log 等等,可以存取當下 Scope 內的任意變數。

 

Settings

在 DevTools 的設定中,可以找到 BlackboxingEnable JavaScript source maps

Blackboxing 能夠 blackbox 符合特定 Pattern 的檔案,另外勾選 Blackbox content scripts 則可以 Blackbox 所有 Extension 的 Content script,不過想要完全避免 Extension 的干擾,還是開啟無痕模式會比較保險。

Preferences > Sources 內可以開關 JavaScript 的 Source map,預設為開啟,也就是自動讀取 Source map 檔案。

 

Blackbox script

Debug 時可以把某些程式碼加入 Blackbox,也就是黑箱作業,當一個檔案被 Blackbox 後,逐步執行系列就不會跳入該程式碼,不過還是有可能經由斷點暫停在 Blackbox 的程式碼中。

Debug 時可以把有把握的檔案 Blackbox 掉,例如寫過完整測試或皆為 Pure function 的程式碼、第三方套件、Extension 的 Content scripts 等等來減少干擾。

在程式碼中點擊右鍵就會看到 Blackbox script 的選項,也可以透過再次點擊 Stop blackboxing 解除。

 

Source map

目前越來越多網頁的程式碼都會經過處理,實際使用時和開發時看到的並不同,而處理過的程式碼通常會被壓縮,幾乎不能用來 Debug,因此使用 Sources 面板進行 Debug 時常常會需要 Source map 來映射目前執行的程式碼到原始碼上,關於 Source map 更多的介紹可以參考 Sources - Files

Sources 面板中也有提供 format 的功能,點擊程式碼面板的左下角的Pretty print xxx.js 圖示會開啟另一份經過排版的程式碼,名稱為 xxx.js:formatted,當程式碼的格式太過混亂或是想要對別人的程式碼做壞事時能大大提升可讀性。

也是因此編輯來自 Formatted 或 Source map 的檔案都是無效的,只有修改原始檔案並存檔才能立即覆寫當前程式碼的行為。

 

小結

善用 Sources 面板的 JavaScript Debugging 功能可以提升 Debug 的效率,雖然 console.log 真的很誘人,也常常是個好方法,但嘗試一下 Sources 面板或許能夠改變未來的 Debug 方式哦。


上一篇
[Day 13] Sources - Step-by-Step Execution
下一篇
[Day 15] Network - Overview & Settings
系列文
你所不知道的各種前端 Debug 技巧30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言