跳到主要內容
黯羽輕揚每天積累一點點

Node 服務如何調試

免費2016-03-27#Node#Node调试#Node调试工具#Node Debugger#node inspector

為什麼需要調試?非要調試的話,怎麼做?

寫在前面

Q:Node 要怎麼調試?

A:啥叫調試?

一般我們所說的「調試」應該是指步過、步入、步出,盯著源碼一句一句執行吧。這樣的話,調試服務端的程序和一般客戶端程序沒什麼區別,都是想要窺視執行流、調用棧、變量當前值等等,也就是說調試 Node 服務和調試頁面中 JS 腳本的方式一樣

當然,服務端有服務端的特殊性,很多代碼與客戶端環境密切相關,比如 Cookie、Request Header、localStorage 等等,想要一行一行調試似乎不太現實,首先,服務的輸入(客戶端請求)從哪裡來?可以模擬請求,也可以直接模擬數據。。。再扯下去其實是測試的內容了,不是「調試」

一。Debugger

Node 內建了斷點調試,也就是 debugger 語句,如下:

// console.js
debugger;

var value = 1;

var fn1 = function() {
debugger;
    value = '2';
    console.log('fn1');
};
var fn2 = function() {
debugger;
    value = 3;
    fn1();
    console.log('fn2');
};

console.log(1);

process.nextTick(function () {
debugger;
    value = 4;
    fn2();
    console.log(2);
});

console.log(3);

其中 debugger; 表示設置斷點,異步 執行流也會被斷點中斷。當然,debugger 只在調試環境有效,通過命令行進入 debug 模式:

node debug ./console.js
// 對於已經在運行的服務,向其進程發送 SIGUSR1 信號可以進入調試模式
// kill -s USR1 [pid]

然後可以看到提示信息和 debug 交互提示:

< Debugger listening on port 5858
debug> . ok
break in E:\node\learn\debug\console.js:1
> 1 debugger;
  2
  3 var value = 1;
debug> 

執行流停在了第一行的 debugger; 處,光標跳動等待輸入調試命令,Node 沒有對 V8 調試命令提供完整支持,可用命令如下:

###1. 控制執行流

  • c/cont

    繼續執行到下一個斷點

  • n/next

    執行到下一句

  • s/step

    步進到函數內部

  • o/out

    從函數內部跳出

  • pause

    暫停執行

比如輸入 c 會輸出 1 和 3,然後停在 value = 4; 的上一行。再輸入 n 會停在 value = 4;,然後先輸入 n 再輸入 s 就進入 fn2 的函數體,停在函數體第一行。。。

注意:調試命令不太友好,如果程序全部執行完畢了,再輸入 c,就需要kill 進程 結束調試了

###2. 設置/清除斷點

  • sb()/setBreakpoint()

    在當前行設置斷點

  • sb(line)/...

    在第 line 行設置斷點

  • sb('fn()')/...

    在函數體的開頭設置斷點

  • sb('script.js', 1)/...

    在 script.js 文件的第一行設置斷點

  • cb()/clearBeakpoint()

    清除斷點

注意:這些命令很不好用,建議在源碼中用 debugger; 語句設置斷點

###3. 查看狀態信息

  • bt/backtrace

    輸出當前堆棧信息

  • list(3)

    列出當前前後各 3 行源碼

  • watch('expr')

    添加 expr 到觀察列表

  • unwatch('expr')

    從觀察列表刪除 expr

  • watchers

    列出觀察列表中所有表達式和值

  • repl

    打開調試的上下文,直接輸入調試代碼

這些命令挺好用,watch 頻繁變化的變量/表達式,或者直接 repl 進入調試環境中的調試環境,想輸出什麼都行

二。調試工具

手動輸入命令比較麻煩,所以有了調試工具:node-inspector,npm 全域安裝,然後直接運行起來:

E:\node\learn\debug>node-inspector
Node Inspector v0.12.7
Visit http://127.0.0.1:8080/?port=5858 to start debugging.
Cannot send response - there is no front-end connection.

瀏覽器(瀏覽器必須帶有Blink 開發者工具,比如 Chrome 和 Opera,而 FF45 不行)訪問 http://127.0.0.1:8080/?port=5858,啥都沒有啊,等等,最後一行說沒找到要調的東西,那好,我們運行程序並進入 debug 模式:

node debug ./console.js
// 當然,向進程發送 SIGUSR1 信號也可以
// kill -s USR1 [pid]

然後刷新瀏覽器,頁面出現源碼了,並且顯示了熟悉的 Dev Tools:

(function (exports, require, module, __filename, __dirname) { debugger;

var value = 1;

var fn1 = function() {
debugger;
    value = '2';
    console.log('fn1');
};
var fn2 = function() {
debugger;
    value = 3;
    fn1();
    console.log('fn2');
};

console.log(1);

process.nextTick(function () {
debugger;
    value = 4;
    fn2();
    console.log(2);
});

console.log(3);
});

發現代碼被模組包裝了,所以調試的一個優勢 是可以窺探 node 源碼,想要追根溯源,無限步入就可以扯出一整條執行流。同理,也可以方便的查看第三方模組內部的具體執行流,分析源碼時比較有用

P.S. 這裡先運行 node-inspector 是為了說明先後順序無所謂,不必每次都嚴格地先 debug 執行待調試的程序,原理是 node 提供了 TCP 調試協議,通過協議可以從進程外部進行調試,node-inspector 通過該協議與待調試的進程通信,執行 debugger 命令,並通過 Blink 開發者工具界面顯示出來

三。總結

其實無論是使用命令還是用工具,感覺都比較麻煩,而且,為什麼需要調試?

理由,筆者只能想到 2 種情況:

  • 代碼糊了(發生了奇怪的錯誤,單純靜態分析找不到錯誤原因)

搞不清執行流了,需要捋一捋

  • 想要分析源碼

弱類型的 js 沒有辦法轉到定義,通過調試分析源碼是不錯的選擇

調試會引起執行中斷,必須離線進行。開發中需要一行一行盯著走的情況極少,應該通過單元測試 保證代碼健壯性,而不是一出問題就調��

對於服務端程序,除單元測試(mocha, should, muk, rewire,內容比較多,我們以後再說)外,日誌(pm2 自帶簡單的錯誤日誌)也是非常必要的。通過分析日誌鎖定錯誤原因,進而找到相應的單元測試用例,進行修復

參考資料

  • 《深入淺出 NodeJS》

評論

暫無評論,快來發表你的看法吧

提交評論