性能测量 API#

稳定性:2 - 稳定

该模块提供了 W3C Web 性能 API 子集的实现,以及用于 Node.js 特定性能测量的附加 API。

Node.js 支持以下 Web 性能 API

import { performance, PerformanceObserver } from 'node:perf_hooks';

const obs = new PerformanceObserver((items) => {
  console.log(items.getEntries()[0].duration);
  performance.clearMarks();
});
obs.observe({ type: 'measure' });
performance.measure('Start to Now');

performance.mark('A');
doSomeLongRunningProcess(() => {
  performance.measure('A to Now', 'A');

  performance.mark('B');
  performance.measure('A to B', 'A', 'B');
});
const { PerformanceObserver, performance } = require('node:perf_hooks');

const obs = new PerformanceObserver((items) => {
  console.log(items.getEntries()[0].duration);
});
obs.observe({ type: 'measure' });
performance.measure('Start to Now');

performance.mark('A');
(async function doSomeLongRunningProcess() {
  await new Promise((r) => setTimeout(r, 5000));
  performance.measure('A to Now', 'A');

  performance.mark('B');
  performance.measure('A to B', 'A', 'B');
})();

perf_hooks.performance#

一个可用于从当前 Node.js 实例收集性能指标的对象。它类似于浏览器中的 window.performance

performance.clearMarks([name])#

如果未提供 name,则从性能时间轴中删除所有 PerformanceMark 对象。如果提供了 name,则仅删除指定的标记。

performance.clearMeasures([name])#

如果未提供 name,则从性能时间轴中删除所有 PerformanceMeasure 对象。如果提供了 name,则仅删除指定的度量。

performance.clearResourceTimings([name])#

如果未提供 name,则从资源时间轴中删除所有 PerformanceResourceTiming 对象。如果提供了 name,则仅删除指定的资源。

performance.eventLoopUtilization([utilization1[, utilization2]])#

这是 perf_hooks.eventLoopUtilization() 的别名。

此属性是 Node.js 的扩展,在 Web 浏览器中不可用。

performance.getEntries()#

返回按 performanceEntry.startTime 排序的 PerformanceEntry 对象列表。如果您只对特定类型或名称的性能条目感兴趣,请参阅 performance.getEntriesByType()performance.getEntriesByName()

performance.getEntriesByName(name[, type])#

返回 performanceEntry.name 等于 name(且可选地 performanceEntry.entryType 等于 type)的 PerformanceEntry 对象列表,并按 performanceEntry.startTime 排序。

performance.getEntriesByType(type)#

返回 performanceEntry.entryType 等于 typePerformanceEntry 对象列表,并按 performanceEntry.startTime 排序。

performance.mark(name[, options])#

  • name <string>
  • options <Object>
  • detail <any> 随标记包含的附加可选详细信息。
  • startTime <number> 用于标记时间的可选时间戳。默认值: performance.now()

在性能时间轴中创建一个新的 PerformanceMark 条目。PerformanceMarkPerformanceEntry 的子类,其 performanceEntry.entryType 始终为 'mark'performanceEntry.duration 始终为 0。性能标记用于标记性能时间轴中的特定重要时刻。

创建的 PerformanceMark 条目会被放入全局性能时间轴中,并可通过 performance.getEntriesperformance.getEntriesByNameperformance.getEntriesByType 进行查询。执行观察时,应使用 performance.clearMarks 手动从全局性能时间轴中清除条目。

performance.markResourceTiming(timingInfo, requestedUrl, initiatorType, global, cacheMode, bodyInfo, responseStatus[, deliveryType])#

此属性是 Node.js 的扩展,在 Web 浏览器中不可用。

在资源时间轴中创建一个新的 PerformanceResourceTiming 条目。PerformanceResourceTimingPerformanceEntry 的子类,其 performanceEntry.entryType 始终为 'resource'。性能资源用于标记资源时间轴中的时刻。

创建的 PerformanceMark 条目会被放入全局资源时间轴中,并可通过 performance.getEntriesperformance.getEntriesByNameperformance.getEntriesByType 进行查询。执行观察时,应使用 performance.clearResourceTimings 手动从全局性能时间轴中清除条目。

performance.measure(name[, startMarkOrOptions[, endMark]])#

  • name <string>
  • startMarkOrOptions <string> | <Object> 可选。
    • detail <any> 随度量包含的附加可选详细信息。
    • duration <number> 开始时间和结束时间之间的持续时间。
    • end <number> | <string> 用作结束时间的时间戳,或标识先前记录的标记的字符串。
    • start <number> | <string> 用作开始时间的时间戳,或标识先前记录的标记的字符串。
  • endMark <string> 可选。如果 startMarkOrOptions 是一个 <Object>,则必须省略此参数。

在性能时间轴中创建一个新的 PerformanceMeasure 条目。PerformanceMeasurePerformanceEntry 的子类,其 performanceEntry.entryType 始终为 'measure'performanceEntry.duration 用于测量 startMarkendMark 之间经过的毫秒数。

startMark 参数可以标识性能时间轴中任何“现有”的 PerformanceMark,或者“可以”标识由 PerformanceNodeTiming 类提供的任何时间戳属性。如果指定的 startMark 不存在,则会抛出错误。

可选的 endMark 参数必须标识性能时间轴中任何“现有”的 PerformanceMark,或 PerformanceNodeTiming 类提供的任何时间戳属性。如果未传递参数,endMark 将默认为 performance.now();否则,如果指定的 endMark 不存在,则会抛出错误。

创建的 PerformanceMeasure 条目会被放入全局性能时间轴中,并可通过 performance.getEntriesperformance.getEntriesByNameperformance.getEntriesByType 进行查询。执行观察时,应使用 performance.clearMeasures 手动从全局性能时间轴中清除条目。

performance.nodeTiming#

此属性是 Node.js 的扩展,在 Web 浏览器中不可用。

PerformanceNodeTiming 类的一个实例,为特定的 Node.js 操作里程碑提供性能指标。

performance.now()#

返回当前高分辨率毫秒级时间戳,其中 0 代表当前 node 进程的开始时间。

performance.setResourceTimingBufferSize(maxSize)#

将全局性能资源计时缓冲区大小设置为指定数量的“资源”类型性能条目对象。

默认情况下,最大缓冲区大小设置为 250。

performance.timeOrigin#

timeOrigin 指定当前 node 进程开始时的高分辨率毫秒级时间戳(以 Unix 时间衡量)。

performance.timerify(fn[, options])#

这是 perf_hooks.timerify() 的别名。

此属性是 Node.js 的扩展,在 Web 浏览器中不可用。

performance.toJSON()#

performance 对象的 JSON 表示形式。它类似于浏览器中的 window.performance.toJSON

事件: 'resourcetimingbufferfull'#

当全局性能资源计时缓冲区满时,会触发 'resourcetimingbufferfull' 事件。请使用 performance.setResourceTimingBufferSize() 调整资源计时缓冲区大小,或者在事件监听器中使用 performance.clearResourceTimings() 清除缓冲区,以允许更多条目添加到性能时间轴缓冲区。

类:PerformanceEntry#

此类的构造函数不会直接暴露给用户。

performanceEntry.duration#

此条目经过的总毫秒数。并非所有性能条目类型此值都有意义。

performanceEntry.entryType#

性能条目的类型。它可能是以下之一:

  • 'dns' (仅限 Node.js)
  • 'function' (仅限 Node.js)
  • 'gc' (仅限 Node.js)
  • 'http2' (仅限 Node.js)
  • 'http' (仅限 Node.js)
  • 'mark' (Web 可用)
  • 'measure' (Web 可用)
  • 'net' (仅限 Node.js)
  • 'node' (仅限 Node.js)
  • 'resource' (Web 可用)

performanceEntry.name#

性能条目的名称。

performanceEntry.startTime#

标记性能条目开始时间的高分辨率毫秒级时间戳。

类:PerformanceMark#

公开通过 Performance.mark() 方法创建的标记。

performanceMark.detail#

在使用 Performance.mark() 方法创建时指定的附加详细信息。

类:PerformanceMeasure#

公开通过 Performance.measure() 方法创建的度量。

此类的构造函数不会直接暴露给用户。

performanceMeasure.detail#

在使用 Performance.measure() 方法创建时指定的附加详细信息。

类: PerformanceNodeEntry#

此类是 Node.js 的扩展。它在 Web 浏览器中不可用。

提供详细的 Node.js 计时数据。

此类的构造函数不会直接暴露给用户。

performanceNodeEntry.detail#

特定于 entryType 的附加详细信息。

performanceNodeEntry.flags#

稳定性: 0 - 已弃用: 请改用 performanceNodeEntry.detail

performanceEntry.entryType 等于 'gc' 时,performance.flags 属性包含有关垃圾回收操作的附加信息。该值可能是以下之一:

  • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_NO
  • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED
  • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_FORCED
  • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING
  • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE
  • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY
  • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE

performanceNodeEntry.kind#

稳定性: 0 - 已弃用: 请改用 performanceNodeEntry.detail

performanceEntry.entryType 等于 'gc' 时,performance.kind 属性标识发生的垃圾回收操作类型。该值可能是以下之一:

  • perf_hooks.constants.NODE_PERFORMANCE_GC_MAJOR
  • perf_hooks.constants.NODE_PERFORMANCE_GC_MINOR
  • perf_hooks.constants.NODE_PERFORMANCE_GC_INCREMENTAL
  • perf_hooks.constants.NODE_PERFORMANCE_GC_WEAKCB

垃圾回收 ('gc') 详细信息#

performanceEntry.type 等于 'gc' 时,performanceNodeEntry.detail 属性将是一个包含两个属性的 <Object>

  • kind <number> 以下之一:
    • perf_hooks.constants.NODE_PERFORMANCE_GC_MAJOR
    • perf_hooks.constants.NODE_PERFORMANCE_GC_MINOR
    • perf_hooks.constants.NODE_PERFORMANCE_GC_INCREMENTAL
    • perf_hooks.constants.NODE_PERFORMANCE_GC_WEAKCB
  • flags <number> 以下之一:
    • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_NO
    • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED
    • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_FORCED
    • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING
    • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE
    • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY
    • perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE

HTTP ('http') 详细信息#

performanceEntry.type 等于 'http' 时,performanceNodeEntry.detail 属性将是一个包含附加信息的 <Object>

如果 performanceEntry.name 等于 HttpClient,则 detail 将包含以下属性:reqresreq 属性将是一个包含 methodurlheaders<Object>,而 res 属性将是一个包含 statusCodestatusMessageheaders<Object>

如果 performanceEntry.name 等于 HttpRequest,则 detail 将包含以下属性:reqresreq 属性将是一个包含 methodurlheaders<Object>,而 res 属性将是一个包含 statusCodestatusMessageheaders<Object>

这可能会增加额外的内存开销,仅应出于诊断目的使用,不应默认在生产环境中开启。

HTTP/2 ('http2') 详细信息#

performanceEntry.type 等于 'http2' 时,performanceNodeEntry.detail 属性将是一个包含附加性能信息的 <Object>

如果 performanceEntry.name 等于 Http2Stream,则 detail 将包含以下属性:

  • bytesRead <number> 为此 Http2Stream 接收的 DATA 帧字节数。
  • bytesWritten <number> 为此 Http2Stream 发送的 DATA 帧字节数。
  • id <number> 关联的 Http2Stream 的标识符。
  • timeToFirstByte <number>PerformanceEntrystartTime 到接收到第一个 DATA 帧所经过的毫秒数。
  • timeToFirstByteSent <number>PerformanceEntrystartTime 到发送第一个 DATA 帧所经过的毫秒数。
  • timeToFirstHeader <number>PerformanceEntrystartTime 到接收到第一个标头所经过的毫秒数。

如果 performanceEntry.name 等于 Http2Session,则 detail 将包含以下属性:

  • bytesRead <number> 为此 Http2Session 接收的字节数。
  • bytesWritten <number> 为此 Http2Session 发送的字节数。
  • framesReceived <number> Http2Session 接收到的 HTTP/2 帧数量。
  • framesSent <number> Http2Session 发送的 HTTP/2 帧数量。
  • maxConcurrentStreams <number> Http2Session 生命周期内同时打开的最大流数量。
  • pingRTT <number> 从传输 PING 帧到接收到其确认所经过的毫秒数。仅在 Http2Session 上发送过 PING 帧时才存在。
  • streamAverageDuration <number> 所有 Http2Stream 实例的平均持续时间(以毫秒为单位)。
  • streamCount <number> Http2Session 处理的 Http2Stream 实例数量。
  • type <string> 'server''client',用于标识 Http2Session 的类型。

Timerify ('function') 详细信息#

performanceEntry.type 等于 'function' 时,performanceNodeEntry.detail 属性将是一个列出被计时函数输入参数的 <Array>

Net ('net') 详细信息#

performanceEntry.type 等于 'net' 时,performanceNodeEntry.detail 属性将是一个包含附加信息的 <Object>

如果 performanceEntry.name 等于 connect,则 detail 将包含以下属性:hostport

DNS ('dns') 详细信息#

performanceEntry.type 等于 'dns' 时,performanceNodeEntry.detail 属性将是一个包含附加信息的 <Object>

如果 performanceEntry.name 等于 lookup,则 detail 将包含以下属性:hostnamefamilyhintsverbatimaddresses

如果 performanceEntry.name 等于 lookupService,则 detail 将包含以下属性:hostporthostnameservice

如果 performanceEntry.name 等于 queryxxxgetHostByAddr,则 detail 将包含以下属性:hostttlresultresult 的值与 queryxxxgetHostByAddr 的结果相同。

类: PerformanceNodeTiming#

此属性是 Node.js 的扩展,在 Web 浏览器中不可用。

提供 Node.js 本身的计时详细信息。此类的构造函数不会暴露给用户。

performanceNodeTiming.bootstrapComplete#

Node.js 进程完成引导的高分辨率毫秒级时间戳。如果引导尚未完成,则该属性的值为 -1。

performanceNodeTiming.environment#

Node.js 环境初始化完成的高分辨率毫秒级时间戳。

performanceNodeTiming.idleTime#

事件循环在事件循环的事件提供程序(例如 epoll_wait)中处于空闲状态的时间的高分辨率毫秒级时间戳。这不考虑 CPU 使用率。如果事件循环尚未开始(例如在主脚本的第一次滴答中),该属性的值为 0。

performanceNodeTiming.loopExit#

Node.js 事件循环退出时的高分辨率毫秒级时间戳。如果事件循环尚未退出,则该属性的值为 -1。它仅在 'exit' 事件的处理器中才具有非 -1 的值。

performanceNodeTiming.loopStart#

Node.js 事件循环启动时的高分辨率毫秒级时间戳。如果事件循环尚未开始(例如在主脚本的第一次滴答中),该属性的值为 -1。

performanceNodeTiming.nodeStart#

Node.js 进程初始化时的高分辨率毫秒级时间戳。

performanceNodeTiming.uvMetricsInfo#

  • 返回:<Object>
  • loopCount <number> 事件循环迭代次数。
  • events <number> 已由事件处理程序处理的事件数量。
  • eventsWaiting <number> 调用事件提供程序时等待处理的事件数量。

这是 uv_metrics_info 函数的包装器。它返回当前的一组事件循环指标。

建议在执行已使用 setImmediate 调度的函数内使用此属性,以避免在完成当前循环迭代期间调度的所有操作之前收集指标。

const { performance } = require('node:perf_hooks');

setImmediate(() => {
  console.log(performance.nodeTiming.uvMetricsInfo);
});
import { performance } from 'node:perf_hooks';

setImmediate(() => {
  console.log(performance.nodeTiming.uvMetricsInfo);
});

performanceNodeTiming.v8Start#

V8 平台初始化时的高分辨率毫秒级时间戳。

类:PerformanceResourceTiming#

提供有关应用程序资源加载的详细网络计时数据。

此类的构造函数不会直接暴露给用户。

performanceResourceTiming.workerStart#

紧接在分派 fetch 请求之前的高分辨率毫秒级时间戳。如果资源未被工作线程拦截,该属性将始终返回 0。

performanceResourceTiming.redirectStart#

表示启动重定向的获取请求开始时间的高分辨率毫秒级时间戳。

performanceResourceTiming.redirectEnd#

在收到最后一次重定向响应的最后一个字节后立即创建的高分辨率毫秒级时间戳。

performanceResourceTiming.fetchStart#

Node.js 开始获取资源之前的高分辨率毫秒级时间戳。

performanceResourceTiming.domainLookupStart#

Node.js 开始资源域名查找之前的高分辨率毫秒级时间戳。

performanceResourceTiming.domainLookupEnd#

表示 Node.js 完成资源域名查找后的高分辨率毫秒级时间戳。

performanceResourceTiming.connectStart#

表示在 Node.js 开始建立服务器连接以检索资源之前的时间的高分辨率毫秒级时间戳。

performanceResourceTiming.connectEnd#

表示在 Node.js 完成建立服务器连接以检索资源之后的时间的高分辨率毫秒级时间戳。

performanceResourceTiming.secureConnectionStart#

表示在 Node.js 开始握手过程以保护当前连接之前的时间的高分辨率毫秒级时间戳。

performanceResourceTiming.requestStart#

表示在 Node.js 从服务器接收到第一个响应字节之前的时间的高分辨率毫秒级时间戳。

performanceResourceTiming.responseEnd#

表示在 Node.js 接收到资源的最后一个字节后,或在传输连接关闭之前(以先发生者为准)的时间的高分辨率毫秒级时间戳。

performanceResourceTiming.transferSize#

表示获取资源大小(以八位字节为单位)的数字。该大小包括响应标头字段加上响应有效载荷主体。

performanceResourceTiming.encodedBodySize#

表示从获取(HTTP 或缓存)接收到的有效载荷主体大小(以八位字节为单位,在移除任何应用的各种编码前)的数字。

performanceResourceTiming.decodedBodySize#

表示从获取(HTTP 或缓存)接收到的消息主体大小(以八位字节为单位,在移除任何应用的各种编码后)的数字。

performanceResourceTiming.toJSON()#

返回 PerformanceResourceTiming 对象的 JSON 表示形式的 object

类:PerformanceObserver#

PerformanceObserver.supportedEntryTypes#

获取支持的类型。

new PerformanceObserver(callback)#

当新的 PerformanceEntry 实例已添加到性能时间轴时,PerformanceObserver 对象提供通知。

import { performance, PerformanceObserver } from 'node:perf_hooks';

const obs = new PerformanceObserver((list, observer) => {
  console.log(list.getEntries());

  performance.clearMarks();
  performance.clearMeasures();
  observer.disconnect();
});
obs.observe({ entryTypes: ['mark'], buffered: true });

performance.mark('test');
const {
  performance,
  PerformanceObserver,
} = require('node:perf_hooks');

const obs = new PerformanceObserver((list, observer) => {
  console.log(list.getEntries());

  performance.clearMarks();
  performance.clearMeasures();
  observer.disconnect();
});
obs.observe({ entryTypes: ['mark'], buffered: true });

performance.mark('test');

因为 PerformanceObserver 实例会引入自己的额外性能开销,所以不应无限期地订阅通知。用户应在不再需要观察者时立即断开连接。

PerformanceObserver 收到有关新 PerformanceEntry 实例的通知时,会调用 callback。该回调会接收一个 PerformanceObserverEntryList 实例和一个对 PerformanceObserver 的引用。

performanceObserver.disconnect()#

断开 PerformanceObserver 实例与所有通知的连接。

performanceObserver.observe(options)#

  • options <Object>
  • type <string> 单个 <PerformanceEntry> 类型。如果已指定 entryTypes,则不得提供此参数。
  • entryTypes <string[]> 一个字符串数组,标识观察者感兴趣的 <PerformanceEntry> 实例类型。如果未提供,则会抛出错误。
  • buffered <boolean> 如果为 true,观察者回调将使用全局 PerformanceEntry 缓冲条目列表调用。如果为 false,则仅在时间点之后创建的 PerformanceEntry 会发送到观察者回调。默认值: false

<PerformanceObserver> 实例订阅到由 options.entryTypesoptions.type 标识的新 <PerformanceEntry> 实例的通知。

import { performance, PerformanceObserver } from 'node:perf_hooks';

const obs = new PerformanceObserver((list, observer) => {
  // Called once asynchronously. `list` contains three items.
});
obs.observe({ type: 'mark' });

for (let n = 0; n < 3; n++)
  performance.mark(`test${n}`);
const {
  performance,
  PerformanceObserver,
} = require('node:perf_hooks');

const obs = new PerformanceObserver((list, observer) => {
  // Called once asynchronously. `list` contains three items.
});
obs.observe({ type: 'mark' });

for (let n = 0; n < 3; n++)
  performance.mark(`test${n}`);

performanceObserver.takeRecords()#

类:PerformanceObserverEntryList#

PerformanceObserverEntryList 类用于提供对传递给 PerformanceObserverPerformanceEntry 实例的访问。此类的构造函数不会暴露给用户。

performanceObserverEntryList.getEntries()#

返回按 performanceEntry.startTime 排序的 PerformanceEntry 对象列表。

import { performance, PerformanceObserver } from 'node:perf_hooks';

const obs = new PerformanceObserver((perfObserverList, observer) => {
  console.log(perfObserverList.getEntries());
  /**
   * [
   *   PerformanceEntry {
   *     name: 'test',
   *     entryType: 'mark',
   *     startTime: 81.465639,
   *     duration: 0,
   *     detail: null
   *   },
   *   PerformanceEntry {
   *     name: 'meow',
   *     entryType: 'mark',
   *     startTime: 81.860064,
   *     duration: 0,
   *     detail: null
   *   }
   * ]
   */

  performance.clearMarks();
  performance.clearMeasures();
  observer.disconnect();
});
obs.observe({ type: 'mark' });

performance.mark('test');
performance.mark('meow');
const {
  performance,
  PerformanceObserver,
} = require('node:perf_hooks');

const obs = new PerformanceObserver((perfObserverList, observer) => {
  console.log(perfObserverList.getEntries());
  /**
   * [
   *   PerformanceEntry {
   *     name: 'test',
   *     entryType: 'mark',
   *     startTime: 81.465639,
   *     duration: 0,
   *     detail: null
   *   },
   *   PerformanceEntry {
   *     name: 'meow',
   *     entryType: 'mark',
   *     startTime: 81.860064,
   *     duration: 0,
   *     detail: null
   *   }
   * ]
   */

  performance.clearMarks();
  performance.clearMeasures();
  observer.disconnect();
});
obs.observe({ type: 'mark' });

performance.mark('test');
performance.mark('meow');

performanceObserverEntryList.getEntriesByName(name[, type])#

返回 performanceEntry.name 等于 name(且可选地 performanceEntry.entryType 等于 type)的 PerformanceEntry 对象列表,并按 performanceEntry.startTime 排序。

import { performance, PerformanceObserver } from 'node:perf_hooks';

const obs = new PerformanceObserver((perfObserverList, observer) => {
  console.log(perfObserverList.getEntriesByName('meow'));
  /**
   * [
   *   PerformanceEntry {
   *     name: 'meow',
   *     entryType: 'mark',
   *     startTime: 98.545991,
   *     duration: 0,
   *     detail: null
   *   }
   * ]
   */
  console.log(perfObserverList.getEntriesByName('nope')); // []

  console.log(perfObserverList.getEntriesByName('test', 'mark'));
  /**
   * [
   *   PerformanceEntry {
   *     name: 'test',
   *     entryType: 'mark',
   *     startTime: 63.518931,
   *     duration: 0,
   *     detail: null
   *   }
   * ]
   */
  console.log(perfObserverList.getEntriesByName('test', 'measure')); // []

  performance.clearMarks();
  performance.clearMeasures();
  observer.disconnect();
});
obs.observe({ entryTypes: ['mark', 'measure'] });

performance.mark('test');
performance.mark('meow');
const {
  performance,
  PerformanceObserver,
} = require('node:perf_hooks');

const obs = new PerformanceObserver((perfObserverList, observer) => {
  console.log(perfObserverList.getEntriesByName('meow'));
  /**
   * [
   *   PerformanceEntry {
   *     name: 'meow',
   *     entryType: 'mark',
   *     startTime: 98.545991,
   *     duration: 0,
   *     detail: null
   *   }
   * ]
   */
  console.log(perfObserverList.getEntriesByName('nope')); // []

  console.log(perfObserverList.getEntriesByName('test', 'mark'));
  /**
   * [
   *   PerformanceEntry {
   *     name: 'test',
   *     entryType: 'mark',
   *     startTime: 63.518931,
   *     duration: 0,
   *     detail: null
   *   }
   * ]
   */
  console.log(perfObserverList.getEntriesByName('test', 'measure')); // []

  performance.clearMarks();
  performance.clearMeasures();
  observer.disconnect();
});
obs.observe({ entryTypes: ['mark', 'measure'] });

performance.mark('test');
performance.mark('meow');

performanceObserverEntryList.getEntriesByType(type)#

返回 performanceEntry.entryType 等于 typePerformanceEntry 对象列表,并按 performanceEntry.startTime 排序。

import { performance, PerformanceObserver } from 'node:perf_hooks';

const obs = new PerformanceObserver((perfObserverList, observer) => {
  console.log(perfObserverList.getEntriesByType('mark'));
  /**
   * [
   *   PerformanceEntry {
   *     name: 'test',
   *     entryType: 'mark',
   *     startTime: 55.897834,
   *     duration: 0,
   *     detail: null
   *   },
   *   PerformanceEntry {
   *     name: 'meow',
   *     entryType: 'mark',
   *     startTime: 56.350146,
   *     duration: 0,
   *     detail: null
   *   }
   * ]
   */
  performance.clearMarks();
  performance.clearMeasures();
  observer.disconnect();
});
obs.observe({ type: 'mark' });

performance.mark('test');
performance.mark('meow');
const {
  performance,
  PerformanceObserver,
} = require('node:perf_hooks');

const obs = new PerformanceObserver((perfObserverList, observer) => {
  console.log(perfObserverList.getEntriesByType('mark'));
  /**
   * [
   *   PerformanceEntry {
   *     name: 'test',
   *     entryType: 'mark',
   *     startTime: 55.897834,
   *     duration: 0,
   *     detail: null
   *   },
   *   PerformanceEntry {
   *     name: 'meow',
   *     entryType: 'mark',
   *     startTime: 56.350146,
   *     duration: 0,
   *     detail: null
   *   }
   * ]
   */
  performance.clearMarks();
  performance.clearMeasures();
  observer.disconnect();
});
obs.observe({ type: 'mark' });

performance.mark('test');
performance.mark('meow');

perf_hooks.createHistogram([options])#

  • options <Object>
  • lowest <number> | <bigint> 最低可识别值。必须是大于 0 的整数值。默认值: 1
  • highest <number> | <bigint> 最高可记录值。必须是等于或大于 lowest 两倍的整数值。默认值: Number.MAX_SAFE_INTEGER
  • figures <number> 精度位数。必须是介于 15 之间的数字。默认值: 3
  • 返回: <RecordableHistogram>
  • 返回一个 <RecordableHistogram>

    perf_hooks.eventLoopUtilization([utilization1[, utilization2]])#

    eventLoopUtilization() 函数返回一个对象,该对象包含事件循环处于空闲和活动状态的累计持续时间(以高分辨率毫秒计时器衡量)。utilization 值是计算出的事件循环利用率 (ELU)。

    如果主线程上的引导尚未完成,则属性的值为 0。由于引导发生在事件循环内,ELU 可在 工作线程 (Worker threads) 上立即可用。

    utilization1utilization2 都是可选参数。

    如果传入 utilization1,则会计算并返回当前调用的 activeidle 时间与参数之间的增量,以及相应的 utilization 值(类似于 process.hrtime())。

    如果同时传入 utilization1utilization2,则会计算两个参数之间的增量。这是一个便利选项,因为与 process.hrtime() 不同,计算 ELU 比简单的减法更复杂。

    ELU 类似于 CPU 利用率,不同之处在于它仅测量事件循环统计信息,而不测量 CPU 使用率。它代表事件循环花费在事件循环事件提供程序(例如 epoll_wait)之外的时间百分比。不考虑其他 CPU 空闲时间。以下是一个大部分时间处于空闲状态的进程如何获得高 ELU 的示例。

    import { eventLoopUtilization } from 'node:perf_hooks';
    import { spawnSync } from 'node:child_process';
    
    setImmediate(() => {
      const elu = eventLoopUtilization();
      spawnSync('sleep', ['5']);
      console.log(eventLoopUtilization(elu).utilization);
    });
    'use strict';
    const { eventLoopUtilization } = require('node:perf_hooks');
    const { spawnSync } = require('node:child_process');
    
    setImmediate(() => {
      const elu = eventLoopUtilization();
      spawnSync('sleep', ['5']);
      console.log(eventLoopUtilization(elu).utilization);
    });
    

    尽管在运行此脚本时 CPU 大部分时间处于空闲状态,但 utilization 的值为 1。这是因为对 child_process.spawnSync() 的调用阻止了事件循环继续进行。

    传入用户定义的对象而不是之前对 eventLoopUtilization() 的调用的结果将导致未定义的行为。返回值不保证反映事件循环的任何正确状态。

    perf_hooks.monitorEventLoopDelay([options])#

    • options <Object>
    • resolution <number> 采样率(以毫秒为单位)。必须大于零。默认值: 10
  • 返回: <IntervalHistogram>
  • 此属性是 Node.js 的扩展,在 Web 浏览器中不可用。

    创建一个 IntervalHistogram 对象,该对象随时间采样并报告事件循环延迟。延迟将以纳秒为单位报告。

    使用定时器检测近似事件循环延迟之所以有效,是因为定时器的执行专门与 libuv 事件循环的生命周期绑定。也就是说,循环中的延迟会导致定时器执行延迟,而这些延迟正是此 API 旨在检测的内容。

    import { monitorEventLoopDelay } from 'node:perf_hooks';
    
    const h = monitorEventLoopDelay({ resolution: 20 });
    h.enable();
    // Do something.
    h.disable();
    console.log(h.min);
    console.log(h.max);
    console.log(h.mean);
    console.log(h.stddev);
    console.log(h.percentiles);
    console.log(h.percentile(50));
    console.log(h.percentile(99));
    const { monitorEventLoopDelay } = require('node:perf_hooks');
    const h = monitorEventLoopDelay({ resolution: 20 });
    h.enable();
    // Do something.
    h.disable();
    console.log(h.min);
    console.log(h.max);
    console.log(h.mean);
    console.log(h.stddev);
    console.log(h.percentiles);
    console.log(h.percentile(50));
    console.log(h.percentile(99));
    

    perf_hooks.timerify(fn[, options])#

    此属性是 Node.js 的扩展,在 Web 浏览器中不可用。

    用一个测量被包装函数运行时间的新函数包装一个函数。PerformanceObserver 必须订阅 'function' 事件类型,以便访问计时详细信息。

    import { timerify, performance, PerformanceObserver } from 'node:perf_hooks';
    
    function someFunction() {
      console.log('hello world');
    }
    
    const wrapped = timerify(someFunction);
    
    const obs = new PerformanceObserver((list) => {
      console.log(list.getEntries()[0].duration);
    
      performance.clearMarks();
      performance.clearMeasures();
      obs.disconnect();
    });
    obs.observe({ entryTypes: ['function'] });
    
    // A performance timeline entry will be created
    wrapped();
    const {
      timerify,
      performance,
      PerformanceObserver,
    } = require('node:perf_hooks');
    
    function someFunction() {
      console.log('hello world');
    }
    
    const wrapped = timerify(someFunction);
    
    const obs = new PerformanceObserver((list) => {
      console.log(list.getEntries()[0].duration);
    
      performance.clearMarks();
      performance.clearMeasures();
      obs.disconnect();
    });
    obs.observe({ entryTypes: ['function'] });
    
    // A performance timeline entry will be created
    wrapped();
    

    如果被包装函数返回一个 promise,则会将一个 finally 处理程序附加到该 promise,并且在调用 finally 处理程序后报告持续时间。

    类: Histogram#

    histogram.count#

    直方图记录的样本数。

    histogram.countBigInt#

    直方图记录的样本数。

    histogram.exceeds#

    事件循环延迟超过 1 小时最大事件循环延迟阈值的次数。

    histogram.exceedsBigInt#

    事件循环延迟超过 1 小时最大事件循环延迟阈值的次数。

    histogram.max#

    记录的最大事件循环延迟。

    histogram.maxBigInt#

    记录的最大事件循环延迟。

    histogram.mean#

    记录的事件循环延迟的平均值。

    histogram.min#

    记录的最小事件循环延迟。

    histogram.minBigInt#

    记录的最小事件循环延迟。

    histogram.percentile(percentile)#

    返回给定百分位数的值。

    histogram.percentileBigInt(percentile)#

    返回给定百分位数的值。

    histogram.percentiles#

    返回一个详细说明累积百分位数分布的 Map 对象。

    histogram.percentilesBigInt#

    返回一个详细说明累积百分位数分布的 Map 对象。

    histogram.reset()#

    重置收集到的直方图数据。

    histogram.stddev#

    记录的事件循环延迟的标准差。

    类: IntervalHistogram extends Histogram#

    一个在给定间隔内定期更新的 Histogram

    histogram.disable()#

    禁用更新间隔定时器。如果定时器已停止,则返回 true,如果已停止,则返回 false

    histogram.enable()#

    启用更新间隔定时器。如果定时器已启动,则返回 true,如果已启动,则返回 false

    histogram[Symbol.dispose]()#

    当销毁直方图时,禁用更新间隔定时器。

    const { monitorEventLoopDelay } = require('node:perf_hooks');
    {
      using hist = monitorEventLoopDelay({ resolution: 20 });
      hist.enable();
      // The histogram will be disabled when the block is exited.
    }
    

    克隆 IntervalHistogram#

    <IntervalHistogram> 实例可以通过 <MessagePort> 克隆。在接收端,直方图被克隆为一个简单的 <Histogram> 对象,该对象不实现 enable()disable() 方法。

    类: RecordableHistogram extends Histogram#

    histogram.add(other)#

    other 中的值添加到此直方图中。

    histogram.record(val)#

    histogram.recordDelta()#

    计算自上次调用 recordDelta() 以来经过的时间量(以纳秒为单位),并将该量记录在直方图中。

    示例#

    测量异步操作的持续时间#

    以下示例使用 Async Hooks 和性能 API 来测量 Timeout 操作的实际持续时间(包括执行回调所花费的时间)。

    import { createHook } from 'node:async_hooks';
    import { performance, PerformanceObserver } from 'node:perf_hooks';
    
    const set = new Set();
    const hook = createHook({
      init(id, type) {
        if (type === 'Timeout') {
          performance.mark(`Timeout-${id}-Init`);
          set.add(id);
        }
      },
      destroy(id) {
        if (set.has(id)) {
          set.delete(id);
          performance.mark(`Timeout-${id}-Destroy`);
          performance.measure(`Timeout-${id}`,
                              `Timeout-${id}-Init`,
                              `Timeout-${id}-Destroy`);
        }
      },
    });
    hook.enable();
    
    const obs = new PerformanceObserver((list, observer) => {
      console.log(list.getEntries()[0]);
      performance.clearMarks();
      performance.clearMeasures();
      observer.disconnect();
    });
    obs.observe({ entryTypes: ['measure'], buffered: true });
    
    setTimeout(() => {}, 1000);
    'use strict';
    const async_hooks = require('node:async_hooks');
    const {
      performance,
      PerformanceObserver,
    } = require('node:perf_hooks');
    
    const set = new Set();
    const hook = async_hooks.createHook({
      init(id, type) {
        if (type === 'Timeout') {
          performance.mark(`Timeout-${id}-Init`);
          set.add(id);
        }
      },
      destroy(id) {
        if (set.has(id)) {
          set.delete(id);
          performance.mark(`Timeout-${id}-Destroy`);
          performance.measure(`Timeout-${id}`,
                              `Timeout-${id}-Init`,
                              `Timeout-${id}-Destroy`);
        }
      },
    });
    hook.enable();
    
    const obs = new PerformanceObserver((list, observer) => {
      console.log(list.getEntries()[0]);
      performance.clearMarks();
      performance.clearMeasures();
      observer.disconnect();
    });
    obs.observe({ entryTypes: ['measure'] });
    
    setTimeout(() => {}, 1000);
    

    测量加载依赖项所需的时间#

    以下示例测量 require() 操作加载依赖项的持续时间。

    import { performance, PerformanceObserver } from 'node:perf_hooks';
    
    // Activate the observer
    const obs = new PerformanceObserver((list) => {
      const entries = list.getEntries();
      entries.forEach((entry) => {
        console.log(`import('${entry[0]}')`, entry.duration);
      });
      performance.clearMarks();
      performance.clearMeasures();
      obs.disconnect();
    });
    obs.observe({ entryTypes: ['function'], buffered: true });
    
    const timedImport = performance.timerify(async (module) => {
      return await import(module);
    });
    
    await timedImport('some-module');
    'use strict';
    const {
      performance,
      PerformanceObserver,
    } = require('node:perf_hooks');
    const mod = require('node:module');
    
    // Monkey patch the require function
    mod.Module.prototype.require =
      performance.timerify(mod.Module.prototype.require);
    require = performance.timerify(require);
    
    // Activate the observer
    const obs = new PerformanceObserver((list) => {
      const entries = list.getEntries();
      entries.forEach((entry) => {
        console.log(`require('${entry[0]}')`, entry.duration);
      });
      performance.clearMarks();
      performance.clearMeasures();
      obs.disconnect();
    });
    obs.observe({ entryTypes: ['function'] });
    
    require('some-module');
    

    测量一次 HTTP 往返所需的时间#

    以下示例用于跟踪 HTTP 客户端 (OutgoingMessage) 和 HTTP 请求 (IncomingMessage) 所花费的时间。对于 HTTP 客户端,它意味着从启动请求到接收响应之间的时间间隔;对于 HTTP 请求,它意味着从接收请求到发送响应之间的时间间隔。

    import { PerformanceObserver } from 'node:perf_hooks';
    import { createServer, get } from 'node:http';
    
    const obs = new PerformanceObserver((items) => {
      items.getEntries().forEach((item) => {
        console.log(item);
      });
    });
    
    obs.observe({ entryTypes: ['http'] });
    
    const PORT = 8080;
    
    createServer((req, res) => {
      res.end('ok');
    }).listen(PORT, () => {
      get(`http://127.0.0.1:${PORT}`);
    });
    'use strict';
    const { PerformanceObserver } = require('node:perf_hooks');
    const http = require('node:http');
    
    const obs = new PerformanceObserver((items) => {
      items.getEntries().forEach((item) => {
        console.log(item);
      });
    });
    
    obs.observe({ entryTypes: ['http'] });
    
    const PORT = 8080;
    
    http.createServer((req, res) => {
      res.end('ok');
    }).listen(PORT, () => {
      http.get(`http://127.0.0.1:${PORT}`);
    });
    

    测量 net.connect (仅 TCP) 在连接成功时所需的时间#

    import { PerformanceObserver } from 'node:perf_hooks';
    import { connect, createServer } from 'node:net';
    
    const obs = new PerformanceObserver((items) => {
      items.getEntries().forEach((item) => {
        console.log(item);
      });
    });
    obs.observe({ entryTypes: ['net'] });
    const PORT = 8080;
    createServer((socket) => {
      socket.destroy();
    }).listen(PORT, () => {
      connect(PORT);
    });
    'use strict';
    const { PerformanceObserver } = require('node:perf_hooks');
    const net = require('node:net');
    const obs = new PerformanceObserver((items) => {
      items.getEntries().forEach((item) => {
        console.log(item);
      });
    });
    obs.observe({ entryTypes: ['net'] });
    const PORT = 8080;
    net.createServer((socket) => {
      socket.destroy();
    }).listen(PORT, () => {
      net.connect(PORT);
    });
    

    测量 DNS 在请求成功时所需的时间#

    import { PerformanceObserver } from 'node:perf_hooks';
    import { lookup, promises } from 'node:dns';
    
    const obs = new PerformanceObserver((items) => {
      items.getEntries().forEach((item) => {
        console.log(item);
      });
    });
    obs.observe({ entryTypes: ['dns'] });
    lookup('localhost', () => {});
    promises.resolve('localhost');
    'use strict';
    const { PerformanceObserver } = require('node:perf_hooks');
    const dns = require('node:dns');
    const obs = new PerformanceObserver((items) => {
      items.getEntries().forEach((item) => {
        console.log(item);
      });
    });
    obs.observe({ entryTypes: ['dns'] });
    dns.lookup('localhost', () => {});
    dns.promises.resolve('localhost');