如何使用多種工具調試 Node.js 代碼

已發表: 2022-03-15

Node.js 是一個 JavaScript 運行時,基於與 Google Chrome 瀏覽器中使用的相同的 V8 引擎。 它通常用於構建跨平台的服務器端和終端應用程序。 Node.js 在過去十年中變得越來越流行,因為它易於安裝、使用實用、速度快,並且允許客戶端 Web 開發人員在其他地方利用他們的技能。

但是,軟件開發仍然是一項複雜的任務,您的 Node.js 代碼有時會失敗。 本教程演示了各種工具來幫助調試應用程序並找出問題的原因。

讓我們潛入水中。

調試概述

“調試”是修復軟件缺陷的各種方法的名稱。 修復錯誤通常很簡單。 查找錯誤的原因可能要復雜得多,並且需要花費數小時的時間。

以下部分描述了您將遇到的三種一般類型的錯誤。

語法錯誤

您的代碼不遵循語言規則——例如,當您省略右括號或拼錯諸如console.lag(x)之類的語句時。

一個好的代碼編輯器可以通過以下方式幫助發現常見問題:

  • 對有效或無效語句進行顏色編碼
  • 類型檢查變量
  • 自動完成函數和變量名
  • 突出顯示匹配的括號
  • 自動縮進代碼塊
  • 檢測無法訪問的代碼
  • 重構雜亂的功能

VS Code 和 Atom 等免費編輯器對 Node.js、JavaScript 和 TypeScript(可轉換為 JavaScript)提供了很好的支持。 在保存和測試代碼之前,通常可以發現基本語法問題。

像 ESLint 這樣的代碼 linter 也會報告語法錯誤、縮進錯誤和未聲明的變量。 ESLint 是一個 Node.js 工具,您可以通過以下方式全局安裝:

 npm i eslint -g

您可以使用以下命令從命令行檢查 JavaScript 文件:

 eslint mycode.js

…但是使用編輯器插件更容易,例如用於 VS Code 的 ESLint 或用於 Atom 的 linter-eslint,它們會在您鍵入時自動驗證代碼:

VS 代碼中的 ESlint
VS 代碼中的 ESlint。

邏輯錯誤

您的代碼運行但未按預期工作。 例如,用戶在請求時沒有註銷; 報告顯示不正確的數字; 數據未完全保存到數據庫中; 等等

邏輯錯誤可能由以下原因引起:

  • 使用錯誤的變量
  • 不正確的條件,例如if (a > 5)而不是if (a < 5)
  • 未能考慮運算符優先級的計算,例如1+2*3的結果是 7 而不是 9。

這是不可避免的:您的 Node.js 代碼會在某個時候失敗。 在此處查看您可以使用哪些工具來調試應用程序並找到問題的原因Click to Tweet

運行時(或執行)錯誤

錯誤只有在應用程序執行時才會變得明顯,這通常會導致崩潰。 運行時錯誤可能由以下原因引起:

  • 除以已設置為零的變量
  • 試圖訪問不存在的數組項
  • 嘗試寫入只讀文件

儘管以下開發技術可以提供幫助,但邏輯和運行時錯誤更難發現:

  1. 使用測試驅動開發: TTD 鼓勵您在開發函數之前編寫測試,例如,當 Z 作為參數傳遞時,X 從函數 Y 返回。 這些測試在初始開發和後續更新期間運行,以確保代碼繼續按預期工作。
  2. 使用問題跟踪系統:沒有什麼比聲稱“您的軟件無法運行”的電子郵件更糟糕的了! 問題跟踪系統允許您記錄特定問題、記錄複製步驟、確定優先級、分配開發人員並跟踪修復進度。
  3. 使用源代碼控制: Git 之類的源代碼控制系統將幫助您備份代碼、管理修訂並確定引入錯誤的位置。 在線存儲庫,包括 Github 和 Bitbucket,為小型或開源項目提供免費空間和工具。

您仍然會遇到 Node.js 錯誤,但以下部分描述了定位該難以捉摸的錯誤的方法。

設置適當的 Node.js 環境變量

在主機操作系統中設置的環境變量可以控制 Node.js 應用程序和模塊設置。 最常見的是NODE_ENV ,通常在調試時設置為開發,或者在實時服務器上運行時設置為生產。 使用以下命令在 macOS 或 Linux 上設置環境變量:

 NODE_ENV=development

或在(經典)Windows 命令提示符下:

 set NODE_ENV=development

或 Windows Powershell:

 $env:NODE_ENV="development"

在流行的 Express.js 框架中,將 NODE_ENV 設置為 development 會禁用模板文件緩存並輸出詳細的錯誤消息,這在調試時可能會有所幫助。 其他模塊可能提供類似的功能,您可以在應用程序中添加 NODE_ENV 條件,例如

// running in development mode? const devMode = (process.env.NODE_ENV !== 'production'); if (devMode) { console.log('application is running in development mode'); }

您還可以使用 Node 的 util.debuglog 方法有條件地輸出錯誤消息,例如

import { debuglog } from 'util'; const myappDebug = debuglog('myapp'); myappDebug('log something');

此應用程序僅在 NODE_DEBUG 設置為 myapp 或 * 或 my* 等通配符時才會輸出日誌消息。

使用 Node.js 命令行選項

節點腳本通常使用 node 後跟入口腳本的名稱來啟動:

 node app.js

您還可以設置命令行選項來控制各種運行時方面。 用於調試的有用標誌包括:

  • --check
    語法檢查腳本而不執行
  • --trace-warnings
    當 JavaScript Promises 未解析或拒絕時輸出堆棧跟踪
  • --enable-source-maps
    使用 TypeScript 等轉譯器時顯示源映射
  • --throw-deprecation
    使用已棄用的 Node.js 功能時發出警告
  • --redirect-warnings=file
    將警告輸出到文件而不是 stderr
  • --trace-exit
    調用process.exit()時輸出堆棧跟踪。

將消息輸出到控制台

輸出控制台消息是調試 Node.js 應用程序的最簡單方法之一:

 console.log(`someVariable: ${ someVariable }`);

很少有開發人員意識到還有許多其他控制台方法:

控制台方法描述
.log(msg) 標準控制台消息
.log('%j', obj) 將對象輸出為緊湊的 JSON 字符串
.dir(obj, opt) 漂亮打印對象屬性
.table(obj) 以表格格式輸出數組和對象
.error(msg) 錯誤信息
.count(label) 增加一個命名的計數器和輸出
.countReset(label) 重置命名計數器
.group(label) 縮進一組消息
.groupEnd(label) 終止一個組
.time(label) 啟動一個命名的計時器
.timeLog(label) 報告經過的時間
.timeEnd(label) 停止一個命名的計時器
.trace() 輸出堆棧跟踪(所有函數調用的列表)
.clear() 清除控制台

console.log()還接受逗號分隔值的列表:

 let x = 123; console.log('x:', x); // x: 123

…儘管 ES6 解構提供了類似的輸出,但花費更少:

 console.log({ x }); // { x: 123 }

console.dir()命令以與 util.inspect() 相同的方式漂亮地打印對象屬性:

 console.dir(myObject, { depth: null, color: true });

控制台爭議

一些開發人員聲稱你不應該使用console.log()因為:

  • 您正在更改代碼並且可能會更改某些內容或忘記刪除它,並且
  • 當有更好的調試選項時,就沒有必要了。

不要相信任何聲稱他們從未使用過console.log()的人! 記錄既快又髒,但每個人都在某個時候使用它。 使用您喜歡的任何工具或技術。 修復一個錯誤比你找到它的方法更重要。

使用第三方日誌系統

第三方日誌系統提供更複雜的功能,例如消息傳遞級別、詳細程度、排序、文件輸出、分析、報告等。 流行的解決方案包括cabinet、loglevel、morgan、pino、signale、storyboard、tracer 和winston。

使用 V8 檢查器

V8 JavaScript 引擎提供了一個可以在 Node.js 中使用的調試客戶端。 使用節點檢查啟動應用程序,例如

node inspect app.js

調試器在第一行暫停並顯示 debug> 提示:

 $ node inspect .\mycode.js < Debugger listening on ws://127.0.0.1:9229/143e23fb < For help, see: https://nodejs.org/en/docs/inspector < ok < Debugger attached. < Break on start in mycode.js:1 > 1 const count = 10; 2 3 for (i = 0; i < counter; i++) { debug>

輸入幫助以查看命令列表。 您可以通過輸入以下內容逐步完成應用程序:

  • cont or c : 繼續執行
  • nextn :運行下一個命令
  • steps :進入被調用的函數
  • out or o : 跳出函數並返回調用語句
  • pause :暫停正在運行的代碼
  • watch('myvar') : 觀察一個變量
  • setBreakPoint()sb() :設置斷點
  • restart :重新啟動腳本
  • .exitCtrl | Cmd + D :退出調試器

誠然,這種調試選項既費時又笨拙。 僅在沒有其他選項時使用它,例如當您在遠程服務器上運行代碼並且無法從其他地方連接或安裝其他軟件時。

使用 Chrome 瀏覽器調試 Node.js 代碼

上面使用的 Node.js 檢查選項啟動了一個 Web Socket 服務器,它在 localhost 端口 9229 上進行偵聽。它還啟動了一個基於文本的調試客戶端,但也可以使用圖形客戶端——例如內置於 Google Chrome 和基於 Chrome 的客戶端Chromium、Edge、Opera、Vivaldi 和 Brave 等瀏覽器。

要調試典型的 Web 應用程序,請使用 --inspect 選項啟動它以啟用 V8 調試器的 Web Socket 服務器:

 node --inspect index.js

筆記:

  • index.js 被假定為應用程序的入口腳本。
  • 確保您使用帶有雙破折號的--inspect以確保您不會啟動基於文本的調試器客戶端。
  • 如果您想在文件更改時自動重新啟動應用程序,您可以使用 nodemon 而不是 node。

默認情況下,調試器只接受來自本地機器的傳入連接。 如果您在其他設備、虛擬機或 Docker 容器上運行應用程序,請使用:

 node --inspect=0.0.0.0:9229 index.js
節點檢查
節點檢查選項。

您還可以使用--inspect-brk代替--inspect在第一行停止處理(設置斷點),以便您可以從頭開始逐步執行代碼。

打開基於 Chrome 的瀏覽器並在地址欄中輸入chrome://inspect以查看本地和聯網設備:

鉻檢查工具
Chrome 檢查工具。

如果您的 Node.js 應用程序未顯示為Remote Target ,則:

  • 單擊 Open dedicated DevTools for Node 並選擇地址和端口,或者
  • 檢查Discover network targets ,單擊Configure ,然後添加運行它的設備的 IP 地址和端口。

單擊 Target 的檢查鏈接以啟動 DevTools 調試器客戶端。 使用 DevTools 進行客戶端代碼調試的任何人都應該熟悉這一點:

Chrome 開發者工具
Chrome 開發工具。

切換到面板。 您可以通過點擊 Cmd | 打開任何文件Ctrl + P 並輸入其文件名(例如 index.js)。

但是,將項目文件夾添加到工作區更容易。 這允許您直接從 DevTools 加載、編輯和保存文件(您是否認為這是一個好主意是另一回事!)

  1. 單擊+ 將文件夾添加到工作區
  2. 選擇 Node.js 項目的位置
  3. 點擊同意以允許文件更改

您現在可以從左側目錄樹加載文件:

Chrome DevTools 源面板
Chrome DevTools 源面板。

單擊任何行號以設置由藍色標記表示的斷點。

調試基於斷點。 這些指定調試器應在何處暫停程序執行並顯示程序的當前狀態(變量、調用堆棧等)

您可以在用戶界面中定義任意數量的斷點。 另一種選擇是放置一個調試器; 聲明到您的代碼中,當附加調試器時停止。

加載並使用您的 Web 應用程序到達設置斷點的語句。 在此處的示例中,http://localhost:3000/ 在任何瀏覽器中打開,DevTools 將在第 44 行停止執行:

鉻斷點
鉻斷點。

右側面板顯示:

因停機時間和 WordPress 問題而苦苦掙扎? Kinsta 是旨在節省您時間的託管解決方案! 查看我們的功能
  • 一排操作圖標(見下文)。
  • 監視窗格允許您通過單擊+圖標並輸入變量名稱來監視變量。
  • Breakpoints窗格顯示所有斷點的列表,並允許啟用或禁用它們。
  • Scope窗格顯示所有本地、模塊和全局變量的狀態。 您將最常檢查此窗格。
  • 調用堆棧窗格顯示了為達到這一點而調用的函數的層次結構。

Paused on breakpoint上方顯示了一排操作圖標:

Chrome 斷點圖標
Chrome 斷點圖標。

從左到右,它們執行以下操作:

  • resume execution : 繼續處理直到下一個斷點
  • step over :執行下一個命令,但停留在當前代碼塊內——不要跳轉到它調用的任何函數
  • step into : 執行下一個命令並根據需要跳轉到任何函數
  • step out :繼續處理到函數結束,返回調用命令
  • step : 與step into類似,只是它不會跳轉到異步函數
  • 停用所有斷點
  • pause on exceptions :發生錯誤時停止處理。

條件斷點

有時有必要對斷點進行更多控制。 假設您有一個完成 1,000 次迭代的循環,但您只對最後一次的狀態感興趣:

 for (let i = 0; i < 1000; i++) { // set breakpoint here }

您可以右鍵單擊該行,選擇Add conditional breakpoint ,然後輸入條件,例如i = 999 ,而不是單擊resume execution 999 次:

Chrome 條件斷點
Chrome 條件斷點。

Chrome 以黃色而不是藍色顯示條件斷點。 在這種情況下,斷點僅在循環的最後一次迭代時觸發。

日誌點

日誌點無需任何代碼即可有效實現 console.log()! 當代碼執行任何一行時,可以輸出一個表達式,但它不會停止處理,這與斷點不同。

要添加日誌點,請右鍵單擊任意行,選擇Add log point ,然後輸入表達式,例如'loop counter i', i

Chrome 日誌點
Chrome 日誌點。

在上面的示例中,DevTools 控制台將loop counter i: 0輸出到loop counter i: 999

使用 VS Code 調試 Node.js 應用程序

VS Code 或 Visual Studio Code 是 Microsoft 提供的免費代碼編輯器,在 Web 開發人員中很受歡迎。 該應用程序可用於 Windows、macOS 和 Linux,並使用 Electron 框架中的 Web 技術開發。

VS Code 支持 Node.js 並具有內置的調試客戶端。 大多數應用程序無需任何配置即可調試; 編輯器會自動啟動調試服務器和客戶端。

打開啟動文件(例如 index.js),激活Run and Debug窗格,單擊Run and Debug按鈕,然後選擇Node.js環境。 單擊任意行以激活顯示為紅色圓圈圖標的斷點。 然後,像以前一樣在瀏覽器中打開應用程序——VS Code 在到達斷點時停止執行:

VS 代碼斷點
VS 代碼斷點。

VariablesWatchCall StackBreakpoints窗格與 Chrome DevTools 中顯示的相似。 Loaded Scripts窗格顯示已加載的腳本,儘管許多腳本是 Node.js 內部的。

操作圖標工具欄允許您:

  • resume execution : 繼續處理直到下一個斷點
  • step over :執行下一個命令,但停留在當前函數內——不要跳轉到它調用的任何函數
  • step into :執行下一個命令並跳轉到它調用的任何函數
  • step out :繼續處理到函數結束,返回調用命令
  • 重新啟動應用程序和調試器
  • 停止應用程序和調試器

與 Chrome DevTools 一樣,您可以右鍵單擊任意行以添加Conditional breakpointsLog points

有關詳細信息,請參閱 Visual Studio Code 中的調試。

VS Code 高級調試配置

如果您想在另一台設備、虛擬機上調試代碼,或者需要使用其他啟動選項(例如 nodemon),則可能需要進一步的 VS Code 配置。

VS Code 將調試配置存儲在項目中.vscode目錄內的 launch.json 文件中。 打開Run and Debug窗格,單擊create a launch.json file ,然後選擇Node.js環境來生成此文件。 提供了一個示例配置:

VS Code 調試器配置
VS Code 調試器配置。

可以將任意數量的配置設置定義為"configurations"數組中的對象。 單擊添加配置...並選擇適當的選項。

單個 Node.js 配置可以:

  1. 啟動進程本身,或
  2. 附加到調試 Web Socket 服務器,可能在遠程機器或 Docker 容器上運行。

例如,要定義 nodemon 配置,請選擇Node.js: Nodemon Setup並在必要時更改“程序”入口腳本:

 { // custom configuration "version": "0.2.0", "configurations": [ { "console": "integratedTerminal", "internalConsoleOptions": "neverOpen", "name": "nodemon", "program": "${workspaceFolder}/index.js", "request": "launch", "restart": true, "runtimeExecutable": "nodemon", "skipFiles": [ "<node_internals>/**" ], "type": "pwa-node" } ] }

保存launch.json文件, nodemon (配置“名稱”)出現在Run and Debug窗格頂部的下拉列表中。 單擊綠色運行圖標開始使用該配置並使用 nodemon 啟動應用程序:

使用 nodemon 進行 VS 代碼調試
使用 nodemon 進行 VS Code 調試。

和以前一樣,您可以添加斷點、條件斷點和日誌點。 主要區別在於,當文件被修改時,nodemon 會自動重啟你的服務器。

有關詳細信息,請參閱 VS Code 啟動配置。

以下 VS Code 擴展還可以幫助您調試託管在遠程或隔離服務器環境中的代碼:

  • 遠程——容器:連接到在 Docker 容器中運行的應用程序
  • 遠程——SSH:連接到遠程服務器上運行的應用程序
  • 遠程 - WSL:連接到在 Linux 的 Windows 子系統 (WSL) 上運行的應用程序。

其他 Node.js 調試選項

Node.js 調試指南為一系列文本編輯器和 IDE 提供建議,包括 Visual Studio、JetBrains WebStorm、Gitpod 和 Eclipse。 Atom 提供了一個節點調試擴展,它將 Chrome DevTools 調試器集成到編輯器中。

一旦您的應用程序上線,您可以考慮使用商業調試服務,例如 LogRocket 和 Sentry.io,它們可以記錄和回放真實用戶遇到的客戶端和服務器錯誤。

需要一些幫助調試應用程序? 從這裡開始點擊鳴叫

概括

從歷史上看,JavaScript 調試一直很困難,但在過去十年中已經有了巨大的改進。 選擇與為其他語言提供的選擇一樣好——如果不是更好的話。

使用任何實用的工具來定位問題。 console.log() 用於快速查找 bug 沒有任何問題,但對於更複雜的問題,Chrome DevTools 或 VS Code 可能更可取。 這些工具可以幫助您創建更強大的代碼,並且您將花費更少的時間來修復錯誤。

你發誓的 Node.js 調試實踐是什麼? 在下面的評論部分分享!