Inspector#

稳定性:2 - 稳定

node:inspector 模块提供了一个用于与 V8 inspector(检查器)交互的 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 inspector 后端发送消息,并接收消息响应和通知。

new inspector.Session()#

创建一个 inspector.Session 类的新实例。在将消息发送到 inspector 后端之前,必须通过 session.connect() 连接 inspector 会话。

使用 Session 时,除非手动执行 Runtime.DiscardConsoleEntries 命令,否则 console API 输出的对象将不会被释放。

事件:'inspectorNotification'#

当接收到来自 V8 Inspector 的任何通知时触发。

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

注意:不建议在同线程会话中使用断点,请参阅 断点支持

也可以仅订阅特定方法的通知

事件:<inspector-protocol-method>#

当接收到 method 字段被设置为 <inspector-protocol-method> 值的 inspector 通知时触发。

以下代码片段为 'Debugger.paused' 事件安装了一个监听器,并在程序执行挂起时(例如通过断点)打印程序挂起的原因。

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

注意:不建议在同线程会话中使用断点,请参阅 断点支持

session.connect()#

将会话连接到 inspector 后端。

session.connectToMainThread()#

将会话连接到主线程的 inspector 后端。如果此 API 不是在 Worker 线程中调用,则会抛出异常。

session.disconnect()#

立即关闭会话。所有挂起的消息回调都将收到一个错误。需要再次调用 session.connect() 才能发送消息。重新连接的会话将丢失所有 inspector 状态,例如已启用的代理或已配置的断点。

session.post(method[, params])#

向 inspector 后端发布一条消息。

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 inspector 协议的最新版本发布在 Chrome DevTools 协议查看器 上。

Node.js inspector 支持 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 inspector 后端发送消息,并接收消息响应和通知。

new inspector.Session()#

创建一个 inspector.Session 类的新实例。在将消息发送到 inspector 后端之前,必须通过 session.connect() 连接 inspector 会话。

使用 Session 时,除非手动执行 Runtime.DiscardConsoleEntries 命令,否则 console API 输出的对象将不会被释放。

事件:'inspectorNotification'#

当接收到来自 V8 Inspector 的任何通知时触发。

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

注意:不建议在同线程会话中使用断点,请参阅 断点支持

也可以仅订阅特定方法的通知

事件:<inspector-protocol-method>#

当接收到 method 字段被设置为 <inspector-protocol-method> 值的 inspector 通知时触发。

以下代码片段为 'Debugger.paused' 事件安装了一个监听器,并在程序执行挂起时(例如通过断点)打印程序挂起的原因。

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

注意:不建议在同线程会话中使用断点,请参阅 断点支持

session.connect()#

将会话连接到 inspector 后端。

session.connectToMainThread()#

将会话连接到主线程的 inspector 后端。如果此 API 不是在 Worker 线程中调用,则会抛出异常。

session.disconnect()#

立即关闭会话。所有挂起的消息回调都将收到一个错误。需要再次调用 session.connect() 才能发送消息。重新连接的会话将丢失所有 inspector 状态,例如已启用的代理或已配置的断点。

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

向 inspector 后端发布一条消息。当收到响应时,将通知 callbackcallback 是一个函数,接受两个可选参数:错误和特定于消息的结果。

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

V8 inspector 协议的最新版本发布在 Chrome DevTools 协议查看器 上。

Node.js inspector 支持 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。

inspector.console#

  • 类型:<Object> 用于向远程 inspector 控制台发送消息的对象。
require('node:inspector').console.log('a message');

inspector 控制台与 Node.js 控制台的 API 并不完全对等。

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

  • port <number> 监听 inspector 连接的端口。可选。默认值:CLI 中指定的值。
  • host <string> 监听 inspector 连接的主机。可选。默认值:CLI 中指定的值。
  • wait <boolean> 阻塞直到客户端连接。可选。默认值:false
  • 返回:<Disposable> 一个调用 inspector.close() 的 Disposable 对象。

在指定主机和端口上激活 inspector。等同于 node --inspect=[[host:]port],但可以在 Node 启动后以编程方式执行。

如果 wait 为 true,则会阻塞直到客户端连接到检查端口并将流控制权移交给调试器客户端。

有关 host 参数的使用,请参阅 安全警告

inspector.url()#

返回活动 inspector 的 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://node.org.cn/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://node.org.cn/en/docs/inspector
ws://:3000/51cf8d0e-3c36-4c59-8efd-54519839e56a

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

inspector.waitForDebugger()#

阻塞直到客户端(现有或稍后连接的)发送了 Runtime.runIfWaitingForDebugger 命令。

如果没有活动的 inspector,则会抛出异常。

与 DevTools 集成#

稳定性:1.1 - 活跃开发中

node:inspector 模块提供了一个用于与支持 Chrome DevTools 协议的 devtools 集成的 API。连接到运行中的 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://node.org.cn/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 请求提供响应。这通常在通过 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

inspector.DOMStorage.domStorageItemAdded#

此功能仅在启用了 --experimental-storage-inspection 标志时可用。

DOMStorage.domStorageItemAdded 事件广播到连接的前端。此事件指示已向存储中添加了一个新项。

inspector.DOMStorage.domStorageItemRemoved#

此功能仅在启用了 --experimental-storage-inspection 标志时可用。

DOMStorage.domStorageItemRemoved 事件广播到连接的前端。此事件指示已从存储中移除了一个项。

inspector.DOMStorage.domStorageItemUpdated#

此功能仅在启用了 --experimental-storage-inspection 标志时可用。

DOMStorage.domStorageItemUpdated 事件广播到连接的前端。此事件指示存储项已更新。

inspector.DOMStorage.domStorageItemsCleared#

此功能仅在启用了 --experimental-storage-inspection 标志时可用。

DOMStorage.domStorageItemsCleared 事件广播到连接的前端。此事件指示已清空存储中的所有项。

inspector.DOMStorage.registerStorage#

此功能仅在启用了 --experimental-storage-inspection 标志时可用。

断点支持#

Chrome DevTools 协议的 Debugger 允许 inspector.Session 附加到程序并设置断点以单步调试代码。

但是,应避免使用通过 session.connect() 连接的同线程 inspector.Session 设置断点,因为被附加和挂起的程序正是调试器本身。相反,尝试通过 session.connectToMainThread() 连接到主线程并在工作线程中设置断点,或者通过 WebSocket 连接使用 调试器 程序进行连接。