performance.now() 更适合动画性能测量,因其精度达微秒级且单调递增;而 date.now() 仅毫秒精度、受系统时钟调整影响,易导致负值或突变,破坏帧耗时计算逻辑。

Performance.now() 返回的是以毫秒为单位、精度高达微秒(通常 0.1ms)的高分辨率时间戳,而 Date.now() 仅提供毫秒级精度(且受系统时钟调整影响),因此在动画性能测量中,performance.now() 更适合捕捉帧间细微耗时、识别卡顿或计算真实渲染延迟。
为什么 Date.now() 不适合动画性能测量
Date.now() 基于系统本地时间,存在两个关键缺陷:
- 精度受限:大多数浏览器将其四舍五入到最接近的毫秒,无法反映 sub-millisecond 的执行差异;
- 非单调性:系统时钟可能被 NTP 同步、手动调整或夏令时切换而回拨或跳跃,导致时间差为负或突变,破坏帧耗时计算逻辑。
用 performance.now() 测量单帧耗时(推荐模式)
在 requestAnimationFrame 回调中,用两次 performance.now() 记录开始与结束时间,直接相减得到该帧实际耗时:
let lastTime = performance.now();
function animate() {
const startTime = performance.now();
<p>// 执行渲染逻辑:更新状态、计算、绘制等
update();
render();</p><p>const frameDuration = performance.now() - startTime;
console.log(<code>本帧耗时: ${frameDuration.toFixed(2)} ms</code>);</p><p>// 可选:统计帧间隔(vs 理想 16.67ms)
const frameInterval = startTime - lastTime;
lastTime = startTime;</p><p>requestAnimationFrame(animate);
}
animate();</p>注意:避免在 startTime 之前插入任何可能阻塞或延时的操作(如大量计算、DOM 查询),否则会污染测量起点。
检测长任务与丢帧(结合 Event Timing API 或自定义标记)
仅靠帧内耗时不足以发现主线程阻塞问题。可配合 performance.mark() + performance.measure() 标记关键阶段:
- 在
requestAnimationFrame开始时打标raf-start; - 在渲染完成、准备提交前打标
render-end; - 用
performance.getEntriesByName('render-end')动态读取并计算各阶段耗时。
若某次 raf-start → render-end 耗时明显超过 16ms(例如 >30ms),大概率发生了长任务或强制同步布局,可进一步用 PerformanceObserver 监听 longtask 类型事件辅助定位。
注意事项与常见误区
-
performance.now()返回值是浮点数,但不要依赖其“绝对值”,只用于计算差值; - 避免跨上下文(如 iframe、Worker)直接比较
performance.now()结果,因起始零点不同; - 不要用它替代
Date.now()做日志时间戳或业务计时(如倒计时),因其不反映真实挂钟时间; - 在低端设备或后台标签页中,
requestAnimationFrame可能降频甚至暂停,此时测得的“帧耗时”可能失真,需结合document.hidden判断页面可见性。











