Inspector#

穩定性:2 - 穩定

原始碼: lib/inspector.js

node:inspector 模組提供了一個與 V8 檢查器互動的 API。

它可以透過以下方式訪問

import * as inspector from 'node:inspector/promises';const inspector = require('node:inspector/promises');

import * as inspector from 'node:inspector';const inspector = require('node:inspector');

Promises API#

穩定性:1 - 實驗性

類:inspector.Session#

inspector.Session 用於向 V8 檢查器後端分派訊息,並接收訊息響應和通知。

new inspector.Session()#

建立 inspector.Session 類的新例項。在向檢查器後端分派訊息之前,需要透過 session.connect() 連線檢查器會話。

使用 Session 時,除非我們手動執行 Runtime.DiscardConsoleEntries 命令,否則由控制檯 API 輸出的物件將不會被釋放。

事件:'inspectorNotification'#

當收到來自 V8 檢查器的任何通知時觸發。

session.on('inspectorNotification', (message) => console.log(message.method));
// Debugger.paused
// Debugger.resumed 

注意:不建議在同線程會話中使用斷點,請參閱斷點支援

也可以只訂閱具有特定方法的通知。

事件:<inspector-protocol-method>#

當收到一個檢查器通知,且其 method 欄位設定為 <inspector-protocol-method> 值時觸發。

以下程式碼片段在 'Debugger.paused' 事件上安裝了一個監聽器,並在程式執行暫停時(例如,透過斷點)列印程式暫停的原因。

session.on('Debugger.paused', ({ params }) => {
  console.log(params.hitBreakpoints);
});
// [ '/the/file/that/has/the/breakpoint.js:11:0' ] 

注意:不建議在同線程會話中使用斷點,請參閱斷點支援

session.connect()#

將一個會話連線到檢查器後端。

session.connectToMainThread()#

將一個會話連線到主執行緒的檢查器後端。如果此 API 不是在工作執行緒上呼叫的,則會丟擲異常。

session.disconnect()#

立即關閉會話。所有待處理的訊息回撥都將以錯誤方式被呼叫。需要呼叫 session.connect() 才能再次傳送訊息。重新連線的會話將丟失所有檢查器狀態,例如已啟用的代理或已配置的斷點。

session.post(method[, params])#

向檢查器後端傳送一條訊息。

import { Session } from 'node:inspector/promises';
try {
  const session = new Session();
  session.connect();
  const result = await session.post('Runtime.evaluate', { expression: '2 + 2' });
  console.log(result);
} catch (error) {
  console.error(error);
}
// Output: { result: { type: 'number', value: 4, description: '4' } } 

最新版本的 V8 檢查器協議釋出在 Chrome DevTools 協議檢視器上。

Node.js 檢查器支援 V8 宣告的所有 Chrome DevTools 協議域。Chrome DevTools 協議域提供了一個介面,用於與用於檢查應用程式狀態和監聽執行時事件的執行時代理進行互動。

用法示例#

除了偵錯程式,還可以透過 DevTools 協議使用各種 V8 分析器。

CPU 分析器#

這是一個展示如何使用 CPU 分析器的示例。

import { Session } from 'node:inspector/promises';
import fs from 'node:fs';
const session = new Session();
session.connect();

await session.post('Profiler.enable');
await session.post('Profiler.start');
// Invoke business logic under measurement here...

// some time later...
const { profile } = await session.post('Profiler.stop');

// Write profile to disk, upload, etc.
fs.writeFileSync('./profile.cpuprofile', JSON.stringify(profile)); 
堆分析器#

這是一個展示如何使用 堆分析器的示例。

import { Session } from 'node:inspector/promises';
import fs from 'node:fs';
const session = new Session();

const fd = fs.openSync('profile.heapsnapshot', 'w');

session.connect();

session.on('HeapProfiler.addHeapSnapshotChunk', (m) => {
  fs.writeSync(fd, m.params.chunk);
});

const result = await session.post('HeapProfiler.takeHeapSnapshot', null);
console.log('HeapProfiler.takeHeapSnapshot done:', result);
session.disconnect();
fs.closeSync(fd); 

回撥 API#

類:inspector.Session#

inspector.Session 用於向 V8 檢查器後端分派訊息,並接收訊息響應和通知。

new inspector.Session()#

建立 inspector.Session 類的新例項。在向檢查器後端分派訊息之前,需要透過 session.connect() 連線檢查器會話。

使用 Session 時,除非我們手動執行 Runtime.DiscardConsoleEntries 命令,否則由控制檯 API 輸出的物件將不會被釋放。

事件:'inspectorNotification'#

當收到來自 V8 檢查器的任何通知時觸發。

session.on('inspectorNotification', (message) => console.log(message.method));
// Debugger.paused
// Debugger.resumed 

注意:不建議在同線程會話中使用斷點,請參閱斷點支援

也可以只訂閱具有特定方法的通知。

事件:<inspector-protocol-method>#

當收到一個檢查器通知,且其 method 欄位設定為 <inspector-protocol-method> 值時觸發。

以下程式碼片段在 'Debugger.paused' 事件上安裝了一個監聽器,並在程式執行暫停時(例如,透過斷點)列印程式暫停的原因。

session.on('Debugger.paused', ({ params }) => {
  console.log(params.hitBreakpoints);
});
// [ '/the/file/that/has/the/breakpoint.js:11:0' ] 

注意:不建議在同線程會話中使用斷點,請參閱斷點支援

session.connect()#

將一個會話連線到檢查器後端。

session.connectToMainThread()#

將一個會話連線到主執行緒的檢查器後端。如果此 API 不是在工作執行緒上呼叫的,則會丟擲異常。

session.disconnect()#

立即關閉會話。所有待處理的訊息回撥都將以錯誤方式被呼叫。需要呼叫 session.connect() 才能再次傳送訊息。重新連線的會話將丟失所有檢查器狀態,例如已啟用的代理或已配置的斷點。

session.post(method[, params][, callback])#

向檢查器後端傳送一條訊息。當收到響應時,會通知 callbackcallback 是一個接受兩個可選引數的函式:錯誤和特定於訊息的結果。

session.post('Runtime.evaluate', { expression: '2 + 2' },
             (error, { result }) => console.log(result));
// Output: { type: 'number', value: 4, description: '4' } 

最新版本的 V8 檢查器協議釋出在 Chrome DevTools 協議檢視器上。

Node.js 檢查器支援 V8 宣告的所有 Chrome DevTools 協議域。Chrome DevTools 協議域提供了一個介面,用於與用於檢查應用程式狀態和監聽執行時事件的執行時代理進行互動。

在向 V8 傳送 HeapProfiler.takeHeapSnapshotHeapProfiler.stopTrackingHeapObjects 命令時,不能將 reportProgress 設定為 true

用法示例#

除了偵錯程式,還可以透過 DevTools 協議使用各種 V8 分析器。

CPU 分析器#

這是一個展示如何使用 CPU 分析器的示例。

const inspector = require('node:inspector');
const fs = require('node:fs');
const session = new inspector.Session();
session.connect();

session.post('Profiler.enable', () => {
  session.post('Profiler.start', () => {
    // Invoke business logic under measurement here...

    // some time later...
    session.post('Profiler.stop', (err, { profile }) => {
      // Write profile to disk, upload, etc.
      if (!err) {
        fs.writeFileSync('./profile.cpuprofile', JSON.stringify(profile));
      }
    });
  });
}); 
堆分析器#

這是一個展示如何使用 堆分析器的示例。

const inspector = require('node:inspector');
const fs = require('node:fs');
const session = new inspector.Session();

const fd = fs.openSync('profile.heapsnapshot', 'w');

session.connect();

session.on('HeapProfiler.addHeapSnapshotChunk', (m) => {
  fs.writeSync(fd, m.params.chunk);
});

session.post('HeapProfiler.takeHeapSnapshot', null, (err, r) => {
  console.log('HeapProfiler.takeHeapSnapshot done:', err, r);
  session.disconnect();
  fs.closeSync(fd);
}); 

通用物件#

inspector.close()#

嘗試關閉所有剩餘的連線,阻塞事件迴圈直到所有連線都已關閉。一旦所有連線都關閉,就停用檢查器。

inspector.console#

  • 型別:<Object> 一個用於向遠端檢查器控制檯傳送訊息的物件。
require('node:inspector').console.log('a message'); 

檢查器控制檯與 Node.js 控制檯的 API 不具有對等性。

inspector.open([port[, host[, wait]]])#

  • port <number> 監聽檢查器連線的埠。可選。預設值:在命令列介面(CLI)上指定的值。
  • host <string> 監聽檢查器連線的主機。可選。預設值:在命令列介面(CLI)上指定的值。
  • wait <boolean> 阻塞直到有客戶端連線。可選。預設值:false
  • 返回:<Disposable> 一個呼叫 inspector.close() 的 Disposable 物件。

在指定的主機和埠上啟用檢查器。等同於 node --inspect=[[host:]port],但可以在 Node 啟動後以程式設計方式執行。

如果 `wait` 為 `true`,將阻塞直到有客戶端連線到檢查埠並且流控制已傳遞給偵錯程式客戶端。

請參閱有關 `host` 引數使用的安全警告

inspector.url()#

返回活動檢查器的 URL,如果沒有則返回 `undefined`。

$ node --inspect -p 'inspector.url()'
Debugger listening on ws://127.0.0.1:9229/166e272e-7a30-4d09-97ce-f1c012b43c34
For help, see: https://nodejs.com.tw/en/docs/inspector
ws://127.0.0.1:9229/166e272e-7a30-4d09-97ce-f1c012b43c34

$ node --inspect=localhost:3000 -p 'inspector.url()'
Debugger listening on ws://:3000/51cf8d0e-3c36-4c59-8efd-54519839e56a
For help, see: https://nodejs.com.tw/en/docs/inspector
ws://:3000/51cf8d0e-3c36-4c59-8efd-54519839e56a

$ node -p 'inspector.url()'
undefined 

inspector.waitForDebugger()#

阻塞直到一個客戶端(現有的或稍後連線的)傳送了 `Runtime.runIfWaitingForDebugger` 命令。

如果沒有活動的檢查器,將丟擲異常。

與 DevTools 整合#

穩定性:1.1 - 活躍開發

node:inspector 模組提供了一個 API,用於與支援 Chrome DevTools 協議的開發工具整合。連線到正在執行的 Node.js 例項的 DevTools 前端可以捕獲從該例項發出的協議事件,並相應地顯示它們以方便除錯。以下方法向所有連線的前端廣播一個協議事件。傳遞給這些方法的 params 可以是可選的,具體取決於協議。

// The `Network.requestWillBeSent` event will be fired.
inspector.Network.requestWillBeSent({
  requestId: 'request-id-1',
  timestamp: Date.now() / 1000,
  wallTime: Date.now(),
  request: {
    url: 'https://nodejs.com.tw/en',
    method: 'GET',
  },
}); 

inspector.Network.dataReceived([params])#

此功能僅在啟用 --experimental-network-inspection 標誌時可用。

向連線的前端廣播 Network.dataReceived 事件,或者如果尚未為給定請求呼叫 Network.streamResourceContent 命令,則緩衝資料。

還啟用了 Network.getResponseBody 命令來檢索響應資料。

inspector.Network.dataSent([params])#

此功能僅在啟用 --experimental-network-inspection 標誌時可用。

啟用 Network.getRequestPostData 命令來檢索請求資料。

inspector.Network.requestWillBeSent([params])#

此功能僅在啟用 --experimental-network-inspection 標誌時可用。

向連線的前端廣播 Network.requestWillBeSent 事件。此事件表示應用程式即將傳送一個 HTTP 請求。

inspector.Network.responseReceived([params])#

此功能僅在啟用 --experimental-network-inspection 標誌時可用。

向連線的前端廣播 Network.responseReceived 事件。此事件表示 HTTP 響應已可用。

inspector.Network.loadingFinished([params])#

此功能僅在啟用 --experimental-network-inspection 標誌時可用。

向連線的前端廣播 Network.loadingFinished 事件。此事件表示 HTTP 請求已完成載入。

inspector.Network.loadingFailed([params])#

此功能僅在啟用 --experimental-network-inspection 標誌時可用。

向連線的前端廣播 Network.loadingFailed 事件。此事件表示 HTTP 請求載入失敗。

inspector.Network.webSocketCreated([params])#

此功能僅在啟用 --experimental-network-inspection 標誌時可用。

向連線的前端廣播 Network.webSocketCreated 事件。此事件表示一個 WebSocket 連線已啟動。

inspector.Network.webSocketHandshakeResponseReceived([params])#

此功能僅在啟用 --experimental-network-inspection 標誌時可用。

向連線的前端廣播 Network.webSocketHandshakeResponseReceived 事件。此事件表示已收到 WebSocket 握手響應。

inspector.Network.webSocketClosed([params])#

此功能僅在啟用 --experimental-network-inspection 標誌時可用。

向連線的前端廣播 Network.webSocketClosed 事件。此事件表示一個 WebSocket 連線已關閉。

inspector.NetworkResources.put#

穩定性:1.1 - 活躍開發

此功能僅在啟用 --experimental-inspector-network-resource 標誌時可用。

inspector.NetworkResources.put 方法用於為透過 Chrome DevTools 協議(CDP)發出的 loadNetworkResource 請求提供響應。這通常在源對映(source map)由 URL 指定時觸發,並且 DevTools 前端(如 Chrome)請求該資源以檢索源對映。

此方法允許開發者預定義要為響應此類 CDP 請求而提供的資源內容。

const inspector = require('node:inspector');
// By preemptively calling put to register the resource, a source map can be resolved when
// a loadNetworkResource request is made from the frontend.
async function setNetworkResources() {
  const mapUrl = 'https://:3000/dist/app.js.map';
  const tsUrl = 'https://:3000/src/app.ts';
  const distAppJsMap = await fetch(mapUrl).then((res) => res.text());
  const srcAppTs = await fetch(tsUrl).then((res) => res.text());
  inspector.NetworkResources.put(mapUrl, distAppJsMap);
  inspector.NetworkResources.put(tsUrl, srcAppTs);
};
setNetworkResources().then(() => {
  require('./dist/app');
}); 

更多詳情,請參閱官方 CDP 文件:Network.loadNetworkResource

斷點支援#

Chrome DevTools 協議的 Debugger允許 inspector.Session 附加到程式並設定斷點以單步除錯程式碼。

但是,應避免使用由 session.connect() 連線的同線程 inspector.Session 設定斷點,因為被附加和暫停的程式正是偵錯程式本身。相反,應嘗試透過 session.connectToMainThread() 連線到主執行緒,並在工作執行緒中設定斷點,或者透過 WebSocket 連線使用 偵錯程式 程式進行連線。