利用斷點暫停程式碼後,就能控制程式碼的執行來進行更進一步的 Debug,筆者會在本篇文章介紹如何在 Sources 面板中進行 JavaScript Debugging。
使用 Sources 面板進行 Debug 的流程大致上可分為以下四個步驟
若還不熟悉斷點的建立方式,可以參考 Sources - Breakpoints,接下來的內容會包含控制執行以及檢查變數。
閱讀本文時建議搭配 Demo 頁面 Sources - Step-by-Step Execution,效果更佳。
執行控制就像是程式碼的播放器,有暫停、繼續、跳至點擊處等功能,在控制的過程中觀察變數值的變化,藉此找出程式碼的問題。
當程式碼暫停執行時可以在程式碼的任意位置按下右鍵,選擇 Continue to Here
快轉到該處,略過沒有興趣的部分,當然也可以在該位置新增一個斷點並按下繼續,會有一樣的效果。
有時會想用一幀一幀慢慢播放的方式來看清影片的每個細節,而逐步執行就相當於播放影片時的「下個影格」功能。
面板上方可以很多個箭頭狀圖示,它們都叫做逐步執行,但在某些情況會有不同的行為。
如果對即將執行的 Function 內部沒有興趣,Step over
會跳至該 Function 後方。
以下方程式碼為例,假設目前暫停在 A 行的 double
:
const number = 3;
const result = double(number); // A
console.log(result); // D
function double(n) {
const result = n * 2; // B
return result; // C
}
點擊圖示後會執行 double
內的所有程式碼並停在 D 行的 console.log
。
如果即將執行的 Function 正是問題所在,Step into
會停在該 Function 內的第一行。
假設目前暫停在 A 行的 double
const number = 3;
const result = double(number); // A
console.log(result); // D
function double(n) {
const result = n * 2; // B
return result; // C
}
點擊圖示後會跳至 B 行,也就是 double
的第一行。
確定目前所在的 Function 沒有問題時,Step out
會停在所處 Function 的後方。
假設目前暫停在 double
內的 B 行
const number = 3;
const result = double(number); // A
console.log(result); // D
function double(n) {
const result = n * 2; // B
return result; // C
}
點擊圖示後會執行完目前 Function 內剩下的程式碼,跳至 D 行的 console.log
。
在同步的狀況下 Step into next function call
和 Step
的行為完全相同,遇到非 Built-in Function 就會進入,但非同步的狀況則有以下區別:
以下方包含非同步行為的程式碼為例,直接執行的話數字為以 2、3、1 的順序印出,假設目前停在 A 行:
setTimeout(() => console.log(1), 2000); // A
console.log(2); // B
console.log(3); // C
按下 Step into
會進入 setTimeout
中的 Callback,也就是執行完 B、C 行,停在 D 行。
有注意到中間停了 2 秒才再次停止嗎?
按下 Step
會跳至 B 行,持續按下 Step
則會停在 C、D 行。
執行完
setTimeout
後已經過了 2 秒,console.log(1)
就直接執行了。
兩種 Step 的差別在於 Step into
為了進入 Function 內非同步的程式碼,需執行完同步的部分,而 step
則會停在下一行同步的程式碼,不直接進入非同步的部分。
當程式碼包含多執行緒時,Step into
和 Step
的行為也會有所區別。
以 Worker 開啟另一個執行緒為例子,假設目前停在 A 行:
// index.js
new Worker('worker.js'); // A
console.log('Hello World!'); // B
// worker.js
console.log('Hello Worker!'); // W
按下 Step into
會直接打開 worker.js
並停在 W 行,注意此時已經執行完 B 行了。
按下 Step
會跳至 B 行,再按一下 Step
會停在 W 行。
注意 Sources 面板的右上角會看到多個 Thread,Console 面板的 Context 也會被切換至 Worker。
Hello World!
Hello Worker!
若想要暫時關閉斷點可以透過 Breakpoints 列表中的 Checkbox 開關各個斷點或點擊上方的 Deactivate breakpoints
關閉全部,另外可以在程式碼行號按下右鍵選擇 Never pause here
來避免 debugger
關鍵字觸發暫停。
剛才的例子都以 A、B 等行號來標示暫停的位置,不過要注意在一行有多個 Function 的狀況下,可以分別在 function 前分別建立斷點。
function a() {
console.log('a');
return 1;
}
function b() {
console.log('b')
return 2;
}
console.log(a() + b());
在沒有建立斷點的情況下,Step over
會直接跳至下一行,在 b
Function 前加入斷點或是使用 Step into
執行完 a
Function 才能讓程式碼執行暫停在後方的 b
Function 前。
善用今天提到的跳轉、逐步執行功能,就能任意控制程式碼的執行來 Debug,相較不能中斷又很吃參數內容的 console.log
是不是強大許多呢?
不過除了逐步執行外,還有回溯、斷點管理等功能,下一篇文章將會繼續介紹 JavaScript Debugger 其他重要的功能。