应优先使用performance.now(),因其精度达微秒级、单调递增且不受系统时间调整影响;Date.now()仅毫秒级精度,易受时钟跳变干扰导致负耗时。

直接用 performance.now() 就够了,别碰 Date.now()
它返回的是从页面加载起的高精度时间戳(单位毫秒,实际精度可达微秒级),不受系统时间跳变影响,也不受时区或夏令时干扰。而 Date.now() 只有毫秒级精度,且在用户手动调系统时间时会出错——比如你测出负耗时,八成是被这个坑了。
实操建议:
- 始终在代码段前后各调一次
performance.now(),相减即得真实耗时 - 避免跨异步边界直接相减:比如
start = performance.now(); await api(); end = performance.now();测的是“发起请求到拿到响应”的总延迟,不是函数执行时间 - 若需测量异步函数内部逻辑(如 Promise resolve 后的处理),把
performance.now()放进.then()或await后面
performance.now() 的数值为什么带小数?要不要 Math.round()?
因为它是 DOMHighResTimeStamp 类型,设计上就支持亚毫秒精度(Chrome 下常见 0.001~5μs 步进)。小数不是误差,而是真实分辨率——尤其在循环密集计算、Canvas 渲染或动画帧内逻辑中,差 0.3ms 都可能影响帧率稳定性。
实操建议:
- 日志调试时可用
.toFixed(3)看三位小数,方便比对 - 做性能阈值判断(如“是否超 16ms”)直接用原始浮点数比较,别四舍五入后误判
- 批量采集时保留原始值,后续再聚合(如取 p95、stddev),否则 round 会掩盖抖动特征
为什么在 DevTools Performance 面板里看不到 performance.now() 记录?
它只返回数值,不自动打点、不写入 Performance Timeline。想在面板里可视化,必须配合 performance.mark() 和 performance.measure()。
实操建议:
- 单次测量用
performance.now()最轻量;需要和渲染帧、网络请求对齐分析时,才加mark - 例如:在 React useEffect 里测首屏数据处理耗时,可先
performance.mark('data-process-start'),处理完performance.mark('data-process-end'),再performance.measure('data-process', 'data-process-start', 'data-process-end') - 记得定期调
performance.clearmarks(),否则长期运行页面可能堆积上千个 mark,拖慢 DevTools 加载
多次调用 performance.now() 会影响性能本身吗?
几乎无开销。V8 和 Blink 对它的实现已深度优化,单次调用耗时通常
- 在每轮 requestAnimationFrame 回调里都测同一段代码(比如每帧都
performance.now()两次),高频调用本身不会卡顿,但日志刷屏或后续计算(如存数组、求平均)可能反成瓶颈 - 不要在 for 循环体内部反复调用——不是
now()慢,而是你本该把整个循环包起来测 - 服务端(Node.js)不支持
performance.now(),要用process.hrtime.bigint()或performance.now = () => Date.now()降级(但精度归零)
真正容易被忽略的是:耗时数字本身没意义,关键看上下文。同样 8.2ms,在空闲主线程里只是普通函数,在 input 输入事件回调里就可能造成掉帧。测完别急着优化,先确认它是不是当前路径的热区、有没有被高频调用、是否阻塞了用户可感知的交互。










