程式碼除錯有時候是一種充滿挑戰的工作,如果有一個趁手的除錯工具的話,往往可以做到事半功倍的效果。得益於這些年的快速發展,在 NodeJS 生態中已經有了多種除錯工具可以使用。我們今年就來分享幾個常用的除錯工具。

在 NodeJS 的程式碼除錯中,通常又兩大類除錯方法,一種是列印日誌,另一種是直接除錯程式碼。我們現在來分別說明。

日誌

日誌可以幫助我們記錄在程式執行過程中的一些狀態和錯誤資訊。通過日誌,我們可以快速的找到出問題的程式碼。比如藉助於異常日誌,我們可以快速的定位到具體的程式碼行。

debug 模組

debug 是很多 NodeJS 包和框架使用的日誌工具。這個包的優點是可以通過環境變數的形式細粒度的控制列印哪些日誌。

比如在下面的程式碼中,假設我們先發送了一些請求,然後又接受到了響應資料。

// index.js
const debugHttpIncoming = require('debug')('http:incoming')
const debugHttpOutgoing = require('debug')('http:outgoing') let outgoingRequest = {
url: 'https://google.com'
} // sending some request
debugHttpOutgoing('sending request to %s', outgoingRequest.url) let incomingRequest = {
body: '{"status": "ok"}'
} // serving some request
debugHttpOutgoing('got JSON body %s', incomingRequest.body)

當我們通過如下方式啟動程式的時候:

DEBUG=http:incoming,http:outgoing node index.js

日誌展示如下:

同時,debug 模組還支援 * 萬用字元,我們可以通過 DEBUG=http:* node index.js 獲得上面相同的日誌輸出。

記錄日誌到檔案

通常,我們需要將應用執行的日誌做持久化處理,最簡單的方式就是記錄到檔案。

pino 是一個高效能的日誌模組,與 bunyan 類似,但是效能更好。

以下是幾種日誌模組的效能資料對比:

benchWinston*10000:     2226.117ms
benchBunyan*10000: 1355.229ms
benchDebug*10000: 445.291ms
benchLogLevel*10000: 322.181ms
benchBole*10000: 291.727ms
benchPino*10000: 269.109ms
benchPinoExtreme*10000: 102.239ms

pino 使用非常簡單:

const pino = require('pino')()

pino.info('hello pino')
pino.info('the answer is %d', 42)
pino.error(new Error('an error'))

上面的程式碼,日誌輸出如下:

{"level":30,"time":1632626946507,"pid":77749,"hostname":"everfind-MacBook-Pro.local","msg":"hello pino"}
{"level":30,"time":1632626946508,"pid":77749,"hostname":"everfind-MacBook-Pro.local","msg":"the answer is 42"}
{"level":50,"time":1632626946508,"pid":77749,"hostname":"everfind-MacBook-Pro.local","stack":"Error: an error\n at Object.<anonymous> (/Users/everfind/workspace/ztest/test/pino.js:5:12)\n at Module._compile (internal/modules/cjs/loader.js:1072:14)\n at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)\n at Module.load (internal/modules/cjs/loader.js:937:32)\n at Function.Module._load (internal/modules/cjs/loader.js:778:12)\n at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)\n at internal/main/run_main_module.js:17:47","type":"Error","msg":"an error"}

除錯

NodeJS 內建除錯模組

NodeJS 提供了內建的除錯模組。使用起來非常簡單直接,缺點是沒有 UI 頁面,純命令列操作。

$ node debug index.js

我們通過 debugger 語句來設定斷點。

const express = require('express');
const app = express(); app.get('/', (req, res) => {
debugger;
res.send('ok');
}); app.listen(3000);

內建的除錯模組支援如下命令:

  • cont 或 c –- 繼續執行
  • next 或 n –- 往下一步
  • step 或 s –- 進入函式
  • out 或 o –- 退出函式
  • repl –- 重新整理上下文資訊

V8 Inspector

我們還可以通過 V8 inspector,使用 Chrome 的 DevTools 來除錯 NodeJS 程式碼。

$ node --inspect index.js

上面這條命令,通過 --inspect 引數告訴 NodeJS 啟用 V8 Inspector。之後我們在 Chrome 中輸入 chrome://inspect/,然後找到我們要除錯的那個檔案,就可以使用 Chrome DevTools 除錯程式碼了。

有時候,我們需要在程式碼的入口處開始除錯,則可以通過 --inspect-brk 來在起始地點開始除錯。

$ node --inspect-brk index.js

VSCode

最後我們介紹如何在 VSCode 中除錯程式碼,這也是最高頻使用的。

通常我們可以直接通過選單啟動除錯,就像上面的演示效果那樣。

如果我們需要一些高階設定,VSCode 允許我們配置一個 .vscode/launch.json 檔案,來告訴 VSCode 如何啟動偵錯程式。

預設的配置項如下:

{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceRoot}/index.js"
},
{
"type": "node",
"request": "attach",
"name": "Attach to Port",
"address": "localhost",
"port": 5858
}
]
}

關於每個配置項的作用和具體用法,可以在 VSCode 的文件中查詢。

另外,如果我們在 VSCode 的內建命令列通過 node --inspect 啟動程式的話,會自動啟用 VSCode 的除錯功能。

常見面試知識點、技術解決方案、教程,都可以掃碼關注公眾號“眾裡千尋”獲取,或者來這裡 https://everfind.github.io