效能測量 API#

穩定度:2 - 穩定

此模組提供了 W3C Web Performance API 子集的實作,以及用於 Node.js 專屬效能測量的額外 API。

Node.js 支援下列 Web Performance 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 的擴充,在網頁瀏覽器中不可用。

performance.getEntries()#

回傳依 performanceEntry.startTime 時間順序排列的 PerformanceEntry 物件列表。如果您只對特定類型或名稱的效能項目感興趣,請參閱 performance.getEntriesByType()performance.getEntriesByName()

performance.getEntriesByName(name[, type])#

回傳依 performanceEntry.startTime 時間順序排列的 PerformanceEntry 物件列表,其 performanceEntry.name 等於 name,且(選擇性地)其 performanceEntry.entryType 等於 type

performance.getEntriesByType(type)#

回傳依 performanceEntry.startTime 時間順序排列的 PerformanceEntry 物件列表,其 performanceEntry.entryType 等於 type

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 的擴充,在網頁瀏覽器中不可用。

在資源時間軸中建立一個新的 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 引數必須標識效能時間軸中任何現有的 PerformanceMarkPerformanceNodeTiming 類別提供的任何時間戳記屬性。如果未傳遞參數,endMark 將為 performance.now(),否則如果指定的 endMark 不存在,則會拋出錯誤。

建立的 PerformanceMeasure 項目會放入全域效能時間軸中,並可透過 performance.getEntriesperformance.getEntriesByNameperformance.getEntriesByType 進行查詢。完成觀察後,應使用 performance.clearMeasures 手動從全域效能時間軸中清除這些項目。

performance.nodeTiming#

此屬性是 Node.js 的擴充,在網頁瀏覽器中不可用。

PerformanceNodeTiming 類別的一個實例,提供特定 Node.js 運作里程碑的效能指標。

performance.now()#

回傳目前的高解析度毫秒時間戳記,其中 0 代表當前 node 程序 (process) 的啟動。

performance.setResourceTimingBufferSize(maxSize)#

將全域效能資源計時緩衝區大小設置為指定的 "resource" 類型效能項目物件數量。

預設情況下,最大緩衝區大小設置為 250。

performance.timeOrigin#

timeOrigin 指定當前 node 程序開始的高解析度毫秒時間戳記(以 Unix 時間測量)。

performance.timerify(fn[, options])#

  • fn <Function>
  • options <Object>
    • histogram <RecordableHistogram> 使用 perf_hooks.createHistogram() 建立的直方圖物件,將以奈秒 (nanoseconds) 為單位記錄執行持續時間。

這是 perf_hooks.timerify() 的別名。

此屬性是 Node.js 的擴充,在網頁瀏覽器中不可用。

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 的擴充,在網頁瀏覽器中不可用。

提供詳細的 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 將包含以下屬性:reqres。其中 req 屬性將是包含 methodurlheaders<Object>res 屬性將是包含 statusCodestatusMessageheaders<Object>

如果 performanceEntry.name 等於 HttpRequest,則 detail 將包含以下屬性:reqres。其中 req 屬性將是包含 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 的擴充,在網頁瀏覽器中不可用。

提供 Node.js 本身的計時詳細資訊。此類別的建構函式不對使用者公開。

performanceNodeTiming.bootstrapComplete#

Node.js 程序完成引導 (bootstrapping) 的高解析度毫秒時間戳記。如果引導尚未完成,則該屬性的值為 -1。

performanceNodeTiming.environment#

Node.js 環境初始化的高解析度毫秒時間戳記。

performanceNodeTiming.idleTime#

事件迴圈在事件迴圈的事件提供者(例如 epoll_wait)中處於空閒狀態的時間量的高解析度毫秒時間戳記。這不考慮 CPU 使用率。如果事件迴圈尚未啟動(例如,在主腳本的第一個 tick 中),則該屬性的值為 0。

performanceNodeTiming.loopExit#

Node.js 事件迴圈結束的高解析度毫秒時間戳記。如果事件迴圈尚未結束,則該屬性的值為 -1。它只能在 'exit' 事件的處理常式中具有非 -1 的值。

performanceNodeTiming.loopStart#

Node.js 事件迴圈啟動的高解析度毫秒時間戳記。如果事件迴圈尚未啟動(例如,在主腳本的第一個 tick 中),則該屬性的值為 -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 請求之前的高解析度毫秒時間戳記。如果資源未被 worker 攔截,則該屬性將始終回傳 0。

performanceResourceTiming.redirectStart#

代表發起重新導向的 fetch 開始時間的高解析度毫秒時間戳記。

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#

一個代表擷取資源大小(以位元組為單位)的數字。該大小包括回應標頭欄位加上回應負載主體 (payload body)。

performanceResourceTiming.encodedBodySize#

一個數字,代表從擷取(HTTP 或快取)收到的負載主體大小(以位元組為單位),且在移除任何套用的內容編碼之前。

performanceResourceTiming.decodedBodySize#

一個數字,代表從擷取(HTTP 或快取)收到的訊息主體大小(以位元組為單位),且在移除任何套用的內容編碼之後。

performanceResourceTiming.toJSON()#

回傳 PerformanceResourceTiming 物件之 JSON 表示形式的 object

類別:PerformanceObserver#

PerformanceObserver.supportedEntryTypes#

取得支援的類型。

new PerformanceObserver(callback)#

PerformanceObserver 物件在新的 PerformanceEntry 實例被添加到效能時間軸時提供通知。

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()#

  • 回傳:<PerformanceEntry[]> 儲存在效能觀察者中的目前項目列表,並將其清空。

類別: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.startTime 時間順序排列的 PerformanceEntry 物件列表,其 performanceEntry.name 等於 name,且(選擇性地)其 performanceEntry.entryType 等於 type

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.startTime 時間順序排列的 PerformanceEntry 物件列表,其 performanceEntry.entryType 等於 type

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() 函式回傳一個物件,包含事件迴圈處於空閒 (idle) 和活動 (active) 狀態的累計持續時間,格式為高解析度毫秒計時器。utilization 值是計算出的事件迴圈使用率 (ELU)。

如果主執行緒上的引導尚未完成,則屬性的值為 0。由於引導發生在事件迴圈中,因此 ELU 在 Worker 執行緒 上立即可用。

utilization1utilization2 都是選填參數。

如果傳遞了 utilization1,則會計算並回傳當前呼叫的 activeidle 時間與其之間的差值 (delta),以及對應的 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])#

此屬性是 Node.js 的擴充,在網頁瀏覽器中不可用。

建立一個 IntervalHistogram 物件,隨時間採樣並報告事件迴圈延遲。延遲將以奈秒 (nanoseconds) 為單位報告。

使用計時器來偵測近似的事件迴圈延遲之所以有效,是因為計時器的執行專門與 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])#

  • fn <Function>
  • options <Object>
    • histogram <RecordableHistogram> 使用 perf_hooks.createHistogram() 建立的直方圖物件,將以奈秒 (nanoseconds) 為單位記錄執行持續時間。

此屬性是 Node.js 的擴充,在網頁瀏覽器中不可用。

將函式封裝在一個新函式中,該新函式會測量被封裝函式的執行時間。必須訂閱 'function' 事件類型的 PerformanceObserver 才能存取計時詳細資訊。

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,則會向該 Promise 附加一個 finally 處理常式,並在叫用 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)#

  • percentile <number> 範圍在 (0, 100] 之間的百分位數值。
  • 回傳:<number>

回傳指定百分位數的值。

histogram.percentileBigInt(percentile)#

  • percentile <number> 範圍在 (0, 100] 之間的百分位數值。
  • 回傳:<bigint>

回傳指定百分位數的值。

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 和 Performance 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');