推荐用 performance.now() 测高频函数耗时,因其微秒级精度与单调时钟特性;需多次采样并统计中位数、P95等指标,避免单次测量及额外开销干扰。

用时间戳差值法评估高频函数执行耗时,核心是用 Date.now() 或 performance.now() 在函数前后采集高精度时间点,再相减得出毫秒级(甚至微秒级)耗时。对高频调用场景,关键在于避免测量本身引入显著开销,并注意采样代表性。
优先用 performance.now() 获取高精度时间
Date.now() 只精确到毫秒,且受系统时间调整影响;而 performance.now() 返回浮点数,单位为毫秒,精度通常达微秒级(如 0.1ms),且基于单调递增时钟,不受系统时间跳变干扰,更适合高频、短时函数的性能观测。
- ✅ 推荐写法:const start = performance.now(); fn(); const end = performance.now(); console.log(end - start);
- ❌ 避免写法:Date.now() 用于 sub-millisecond 级别函数(如简单数学运算、数组查找)易因精度不足归零或抖动过大
高频调用下要聚合统计,不能只测单次
单次执行受 JS 引擎优化(如 JIT 编译预热)、CPU 调度、GC 干扰等影响极大,一次测量无意义。应连续运行数百至数千次,记录每次耗时并计算中位数、P95、最大值等指标。
- 示例:循环调用 1000 次,收集所有耗时存入数组,用
arr.sort((a,b)=>a-b)[Math.floor(arr.length/2)]取中位数 - 注意控制变量:确保循环体中只包含目标函数调用和时间采集,避免字符串拼接、console.log 等额外开销混入测量
- 可借助
console.time()/console.timeEnd()快速验证,但仅适合粗略调试,不适用于自动化压测
警惕测量副作用:避免“薛定谔的性能”
在严格高频场景(如 requestAnimationFrame 回调、事件处理器),插入测量代码可能触发 V8 的去优化(deoptimization),导致函数退出优化状态,反而让结果虚高;同时频繁调用 performance.now() 本身也有约 0.01–0.1ms 开销。
立即学习“Java免费学习笔记(深入)”;
- 对策:测量阶段关闭其他监控逻辑;生产环境禁用,仅在 dev 或 benchmark 模式启用
- 进阶技巧:用
performance.mark()+performance.measure()替代手动差值,在大型应用中更易与 DevTools 性能面板联动分析 - 若函数极短(
实际封装一个轻量 benchmark 工具
便于复用、隔离干扰、自动统计:
function bench(fn, times = 1000) {
const durations = [];
for (let i = 0; i < times; i++) {
const start = performance.now();
fn();
const end = performance.now();
durations.push(end - start);
}
const sorted = durations.sort((a, b) => a - b);
return {
mean: sorted.reduce((a, b) => a + b, 0) / times,
median: sorted[Math.floor(times / 2)],
p95: sorted[Math.floor(times * 0.95)],
max: sorted[times - 1]
};
}
<p>// 使用
const result = bench(() => arr.includes(x), 5000);
console.log(result); // { mean: 0.024, median: 0.022, p95: 0.038, max: 0.15 }


















