1. 程式人生 > 實用技巧 >Node.js 深度除錯指南

Node.js 深度除錯指南

在 Node.js 專案開發過程中,隨著專案的發展,呼叫關係越來越複雜,除錯工具的重要性日益凸顯。

Node(v6.3+)集成了方便好用 V8 Inspect 偵錯程式,允許我們通過 Chrome DevTools 進行圖形化的除錯和效能分析。同時,我們也可以使用 VS Code,Webstorm 等支援的編輯器對 Node.js 程式進行除錯。

Node Inspect

要想啟動偵錯程式,我們需要在啟動 Node.js 應用程式時傳入 --inspect 標誌,也可以使用該標誌提供自定義的埠,例如 --inspect=9222 將會在 9222 埠上接受開發者工具的連線。

一段簡單的程式碼

 function
log() { let a = 1; console.log(a); a = 2; console.log(a); } ​ log();



使用 node --inspect 啟動

這時我們會發現,程式直接執行完成了,沒有中斷,導致我們無法使用 Chrome DevTools 進行除錯。對於這種直接執行的程式碼,我們可以使用 --inspect-brk 引數,在應用程式程式碼的第一行終端,然後再進行除錯。

Chrome DevTools

當開啟 Node 除錯後,我們可以開啟 Chrome,訪問 chrome://inspect ,在 Devices 中查詢到我們的 Node.js 程式,點選 inspect 開啟除錯面板進行操作

在除錯工具視窗,我們可以設定斷點,執行程式進行除錯

執行中程式除錯

在某些情況下,我們可以需要對正在執行的 Node.js 程式進行除錯,比如 Express Web 服務。我們不可能停止服務,再以 --inspect 執行除錯。

對於這種情況,我們可以先獲取服務的程序 Id

向指令碼程序傳送 SIGUSR1 訊號,就可以建立除錯連線

kill -SIGUSR1 34943
複製程式碼

在 Windows 平臺下,可以使用下面的命令

 node -e 'process._debugProcess(30464)'



需要注意的是:這種除錯任然會中斷服務程序的執行。

VS Code 除錯

快速除錯

對於簡單的應用程式,可以開啟檔案,按 F5 並選擇除錯型別為 Node,即可進行除錯

使用配置除錯

對於大多數的除錯場景,更推薦使用配置檔案,因為它可以配置並儲存除錯設定的資訊,方便我們下次快速使用。在 VC Code 中,除錯配置通常儲存在 .vscode 資料夾下的 launch.json 檔案中 。可以點選左側欄目中的除錯圖示,快速建立 launch.json 檔案

VS Code 會自動下面類似的 launch.json 除錯配置檔案,其中 program 代表我們需要除錯的檔案路徑,workspaceFolder 為當前工作區的路徑,通常是專案的根目錄

 {
   "version": "0.2.0",
   "configurations": [
     {
       "type": "node",
       "request": "launch",
       "name": "啟動程式",
       "skipFiles": ["<node_internals>/**"],
       "program": "${workspaceFolder}/index.js"
     }
   ]
 }



設定斷點,即可啟動除錯,並在左側的樹檢視中看到變數對應的值以及堆疊資訊

launch.json

launch.json 中有許多不同的屬性,支援不同的偵錯程式和除錯場景,下面的屬性在每個啟動配置中是必須的

  • name - 當前除錯配置項的名稱,可讀性要好,區分每個除錯配置項

  • type - 用於此啟動配置的偵錯程式的型別。每個已安裝的除錯擴充套件都引入一種型別:例如node,php,go 等。

  • request - 當前除錯項的型別,目前支援 launch 和 attach 兩種型別。launch 適合除錯未啟動的程式,attach 則適合除錯已經執行的程式。

一些其他比較有用的選項:

  • program - 啟動偵錯程式時要執行的可執行程式或檔案

  • args - 傳遞給程式進行除錯的引數

  • env - 除錯時的環境變數

  • envFile - 包含環境變數鍵值對的檔案

  • stopOnEntry - 程式啟動時立即中斷

  • port - 連線到正在執行的偵錯程式的埠

  • runtimeExecutable - 啟用除錯的可執行 Runtime,預設是 Node

日誌點 - Logpoints

VS Code 提供了好用的除錯小工具 - 日誌點,日誌點是斷點的一種變體,它不 "中斷 "進入偵錯程式,而是將一條訊息記錄到控制檯,日誌點對於在除錯不能暫停或停止的生產伺服器時注入日誌特別有用。

NPM 指令碼除錯

除了使用 node 啟動 Node.js 專案之外,VS Code 還支援自定義啟動程式 runtime,藉助這個能力,可以直接使用 NPM 啟動除錯。如下面,使用 npm run debug 啟動除錯

 "scripts": {
     "debug": "node --inspect server.js"
  }

launch.json

 {
   "type": "node",
   "request": "launch",
   "name": "NPM 啟動",
   "runtimeExecutable": "npm",
   "runtimeArgs": ["run", "debug"],
   "port": 9229
 }



TypeScript 除錯

VS Code 內建的 Node.js 的偵錯程式支援 JavaScript Source Map,可以結合 Source Map 除錯轉譯前的程式碼,如 TypeScript,壓縮混淆的 JavaScript 程式碼等都可以利用 Source Map 的支援除錯原始碼。

我準備了一個簡單的 TS Server Demo,可以直接 Clone 原始碼本地測試。下面是專案中的 src/index.ts 檔案,建立了一個 HTTP Server

 import * as http from "http";
 ​
 let reqCount = 1;
 ​
 http
   .createServer((req, res) => {
     const message = `Request Count: ${reqCount}`;
 ​
     res.writeHead(200, { "Content-Type": "text/html" });
 ​
     res.end(`<html><div>${message}</div></html>`);
 ​
     console.log("handled request: " + reqCount++);
   })
   .listen(3000);
 ​
 console.log("server running on port 3000");

建立 tsconfig.json 配置,配置編譯生成 Source Map

 {
   "compilerOptions": {
     "outDir": "./dist",
     "sourceMap": true
   },
   "include": ["src/**/*"]
 }



使用 tsc 編譯一下,生成 JS 程式碼:dist/index.js,建立除錯配置,入口檔案為 dist/index.js

 {
   "type": "node",
   "request": "launch",
   "name": "Launch Program",
   "program": "${workspaceFolder}/dist/index.js",
   "skipFiles": ["<node_internals>/**"]
 }

然後打斷點,啟動除錯,瀏覽器訪問 http://localhost:3000,即可看到除錯進入了 TS 檔案

遠端除錯

當我們需要在真實的伺服器等遠端執行環境除錯 Node.js 時,我們可以利用上面提到的方式,在伺服器上開啟 Node.js 除錯功能,並在本地連線上遠端的除錯埠進行除錯。

VS Code 預設支援遠端除錯,我們需要 launch.json 配置檔案中指定遠端服務的 IP 地址以及埠,如下所示:

 {
   "type": "node",
   "request": "attach",
   "name": "遠端除錯",
   "address": "IP 地址",
   "port": "9229"
 }



VS Code 會自動載入遠端的檔案,展示為只讀程式碼供除錯使用。

如果想要在除錯的過程中編輯原始碼,或者更好的除錯體驗,可以在遠端資料夾和本地專案之間設定一個對映。VS Code 提供了 localRoot 和 remoteRoot 屬性來對映本地 VS Code 專案和(遠端)Node.js 資料夾:

 {
   "type": "node",
   "request": "attach",
   "name": "遠端除錯",
   "address": "IP 地址",
   "port": "9229",
   "localRoot": "${workspaceFolder}/src",
   "remoteRoot": "/var/user/"
 }



在建立對映關係後,即可在本地專案進行斷點除錯,遠端的斷點資訊會同步到本地專案,使用起來十分方便。

子程序除錯

與普通程序除錯原理一致,子程序除錯時也需要傳入 --inspect 引數,這一點需要特別注意,否則無法啟動子程序除錯。

如下通過子程序啟動 Server 的例子:

 // fork.js 檔案
 const { spawn } = require("child_process");
 ​
 const sp = spawn("node", ["./fork_server.js"]);
 ​
 console.log("父程序 PID", sp.pid);
 ​
 sp.stdout.on("data", (data) => {
   console.log(`stdout: ${data}`);
 });
 ​
 sp.stderr.on("data", (data) => {
   console.error(`stderr: ${data}`);
 });



如果直接使用 node --inspect 啟動主程序的話,會發現只顯示了主程序的除錯埠,這就是因為我們在程式中啟動子程序時沒有傳遞 --inspect 選項導致的。

這裡我們在啟動程序時新增上 --inspect 引數,同時注意要指定一個預設 9229 埠之外的埠號,避免除錯埠衝突

 - const sp = spawn("node", ["./fork_server.js"]);
 + const sp = spawn("node", ["--inspect=9230", "./fork_server.js"]);



再次啟動,就能看到兩個除錯資訊輸出了

當然,怎麼能少得了強大的 VS Code 呢。VS Code 的 Node 偵錯程式提供了一種機制,可以追蹤所有子程序,並在除錯模式下,自動連結程序。可以通過 autoAttachChildProcesses 屬性開啟此機制:

 {
   "type": "node",
   "request": "launch",
   "name": "啟動程式",
   "program": "${workspaceFolder}/fork.js",
   "autoAttachChildProcesses": true
 }



啟動後,即可對父程序,或子程序進行斷點除錯,效果如下

結語

大家有什麼要說的,歡迎在評論區留言

對了,小編為大家準備了一套2020最新的web前端資料,需要點選下方連結獲取方式

1、點贊+評論(勾選“同時轉發”)

學習前端,你掌握這些。二線也能輕鬆拿8K以上

參考文獻

Debugging - Getting Started | Node.js

Debug Node.js Apps using Visual Studio Code