自v8.5.0版本起,Node.js 新了性能指标收集的API-Performance Timing API,用于应用性能测试及优化。
- Performance Timing API
- Class: Performance
- Class: PerformanceEntry
- Class: PerformanceNodeTiming extends PerformanceEntry
- Class: PerformanceObserver
- Class: PerformanceObserverEntryList
- 示例
1. Performance Timing API
Performance Timing API提供了W3C Performance Timeline规范的实现,目的是支持高分辨率的性能指标收集。这与现代Web浏览器中实现的Performance API相同。
const { PerformanceObserver, performance } = require('perf_hooks');
const obs = new PerformanceObserver((items) => {
console.log(items.getEntries()[0].duration);
performance.clearMarks();
});
obs.observe({ entryTypes: ['measure'] });
performance.mark('A');
doSomeLongRunningProcess(() => {
performance.mark('B');
performance.measure('A to B', 'A', 'B');
});
2. Class: Performance
2.1 performance.clearMarks([name])
name<string>
如果未提供name,则从Performance Timeline中删除所有PerformanceMark对象。如果提供了name,则仅删除指定名称的标记。
2.2 performance.mark([name])
name<string>
在Performance Timeline中创建一个新的PerformanceMark入口点。PerformanceMark是PerformanceEntry的子类,其performanceEntry.entryType始终为'mark',performanceEntry.duration始终是0。性能标记用于标记Performance Timeline中的特定时刻。
2.3 performance.measure(name, startMark, endMark)
name<string>startMark<string>endMark<string>
在Performance Timeline中创建一个新的PerformanceMeasure入口点。PerformanceMeasure是PerformanceEntry的子类,其performanceEntry.entryType始终是'measure',performanceEntry.duration是自startMark和endMark以来经过的毫秒数。
startMark参数可以标识Performance Timeline中的任何现有PerformanceMark,或者可以标识PerformanceNodeTiming类提供的任何时间戳属性。如果指定名的startMark不存在,则默认startMark设置为timeOrigin。
endMark参数必须标识Performance Timeline中的任何现有PerformanceMark或PerformanceNodeTiming类提供的任何时间戳属性。如果指定的endMark不存在,则会引发错误。
2.4 performance.nodeTiming
PerformanceNodeTiming类的一个实例,它为指定的Node.js操作点提供性能指标。
2.5 performance.now()
- 返回:<number>
返回当前的高分辨率毫秒时间戳,其中0表示当前'node'进程的开始。
2.6 performance.timeOrigin
- <number>
timeOrigin规范的当前节点进程开始的高分辨率毫秒时间戳,以Unix时间为单位。
2.7 performance.timerify(fn)
fn<Function>
在新函数中包含一个函数,用于测量包装函数的运行时间。PerformanceObserver必须订阅'function'事件才能访问时序详细信息。
const {
performance,
PerformanceObserver
} = require('perf_hooks');
function someFunction() {
console.log('hello world');
}
const wrapped = performance.timerify(someFunction);
const obs = new PerformanceObserver((list) => {
console.log(list.getEntries()[0].duration);
obs.disconnect();
});
obs.observe({ entryTypes: ['function'] });
// A performance timeline entry will be created
wrapped();
3. Class: PerformanceEntry
3.1 performanceEntry.duration
- <number>
此入口点经过的总毫秒数。对于所有Performance Entry类型,此值都没有意义。
3.2 performanceEntry.name
- <string>
性能入口点的名称。
3.3 performanceEntry.startTime
- <number>
标记Performance Entry开始时间的高分辨率毫秒时间戳。
3.4 performanceEntry.entryType
- <string>
性能入口点类型。当前可能是以下值之一:'node',
'mark', 'measure', 'gc', 'function'或'http2'。
3.5 performanceEntry.kind
- <number>
当performanceEntry.entryType等于'gc'时,performance.kind属性标识发生的垃圾收集操作的类型。该值可能是以下之一:
perf_hooks.constants.NODE_PERFORMANCE_GC_MAJORperf_hooks.constants.NODE_PERFORMANCE_GC_MINORperf_hooks.constants.NODE_PERFORMANCE_GC_INCREMENTALperf_hooks.constants.NODE_PERFORMANCE_GC_WEAKCB
4. Class: PerformanceNodeTiming extends PerformanceEntry
PerformanceNodeTiming类是对PerformanceEntry的扩展类,提供Node.js本身的时序详细信息。
4.1 performanceNodeTiming.bootstrapComplete
- <number>
Node.js进程完成引导的高分辨率毫秒时间戳。如果引导尚未完成,则该属性的值为-1。
4.2 performanceNodeTiming.loopExit
- <number>
Node.js事件循环退出的高分辨率毫秒时间戳。如果事件循环尚未退出,则该属性的值为又-1。它只能在Process的'exit'事件的处理程序中有-1值。
4.3 performanceNodeTiming.loopStart
- <number>
Node.js事件循环开始的高分辨率毫秒时间戳。如果事件循环尚未开始(如,在主脚本的第一个时钟中),则该属性的值为-1。
4.4 performanceNodeTiming.nodeStart
- <number>
初始化Node.js进程的高分辨率毫秒时间戳。
4.5 performanceNodeTiming.v8Start
- <number>
V8平台初始化的高分辨率毫秒时间戳。
5. Class: PerformanceObserver
5.1 new PerformanceObserver(callback)
callback<Function>list<PerformanceObserverEntryList>observer<PerformanceObserver>
PerformanceObserver对象在将新的PerformanceEntry实例添加到Performance Timeline时提供通知。
const {
performance,
PerformanceObserver
} = require('perf_hooks');
const obs = new PerformanceObserver((list, observer) => {
console.log(list.getEntries());
observer.disconnect();
});
obs.observe({ entryTypes: ['mark'], buffered: true });
performance.mark('test');
因为PerformanceObserver的实例引入本身会有额外性能开销,所以实例不应无限期地订阅通知。用户应在不再需要时立即断开连接。
当PerformanceObserver通知新的PerformanceEntry实例时,将调用回调。回调接收PerformanceObserverEntryList实例和对PerformanceObserver的引用。
5.2 performanceObserver.disconnect()
断开PerformanceObserver实例与所有通知的连接。
5.3 performanceObserver.observe(options)
options<object>entryTypes<string[]>字符串数组,用于标识观察者感兴趣的PerformanceEntry实例的类型。如果未提供,将引发错误。buffered<boolean>如果为true,则将使用setImmediate()调用通知回调,并在内部缓冲多个PerformanceEntry实例通知。如果为false,则通知将立即且同步。默认值:false。
将PerformanceObserver实例订阅到options.entryTypes标识的新PerformanceEntry实例的通知。
当options.buffered为false时,将为每个PerformanceEntry实例调用一次回调:
const {
performance,
PerformanceObserver
} = require('perf_hooks');
const obs = new PerformanceObserver((list, observer) => {
// called three times synchronously. list contains one item
});
obs.observe({ entryTypes: ['mark'] });
for (let n = 0; n < 3; n++)
performance.mark(`test${n}`);
const {
performance,
PerformanceObserver
} = require('perf_hooks');
const obs = new PerformanceObserver((list, observer) => {
// called once. list contains three items
});
obs.observe({ entryTypes: ['mark'], buffered: true });
for (let n = 0; n < 3; n++)
performance.mark(`test${n}`);
6. Class: PerformanceObserverEntryList
PerformanceObserverEntryList类用于提供对传递给PerformanceObserver的PerformanceEntry实例的访问。
6.1 performanceObserverEntryList.getEntries()
以performanceEntry.startTime的形式按时间顺序返回PerformanceEntry对象的列表。
6.2 performanceObserverEntryList.getEntriesByName(name[, type])
name<string>type<string>- 返回:<PerformanceEntry[]>
返回PerformanceEntry对象的列表,这些对象按时间顺序依次为performanceEntry.startTime,其performanceEntry.name等于name,并且可选,其performanceEntry.entryType等于type。
6.3 performanceObserverEntryList.getEntriesByType(type)
type<string>- 返回:<PerformanceEntry[]>
返回PerformanceEntry对象的列表,该列表按时间顺序相当于performanceEntry.entryType等于type的performanceEntry.startTime。
7. 示例
测量异步操作的持续时间
以下示例使用Async Hooks和Performance API来测量Timeout操作的实际持续时间(包括执行回调的时间):
'use strict';
const async_hooks = require('async_hooks');
const {
performance,
PerformanceObserver
} = require('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();
observer.disconnect();
});
obs.observe({ entryTypes: ['measure'], buffered: true });
setTimeout(() => {}, 1000);
测量加载依赖项所需的时间
以下示例测量require()操作加载依赖项的持续时间:
'use strict';
const {
performance,
PerformanceObserver
} = require('perf_hooks');
const mod = require('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);
});
obs.disconnect();
});
obs.observe({ entryTypes: ['function'], buffered: true });
require('some-module');
