performance.now()
是 JavaScript 中用于获取高精度时间戳的方法,属于 Web Performance API。它的核心特性和用途如下:
一、核心特性
特性 | 说明 |
---|---|
高精度 | 精度可达 微秒级 (百万分之一秒),而 Date.now() 只有毫秒级 (千分之一秒) |
单调递增 | 时间戳只会增加,不受系统时间修改影响(即使用户修改电脑时间也不会影响结果) |
相对时间起点 | 返回的时间是相对于 页面导航开始时刻 的时间差(页面加载或浏览器 tab 首次打开) |
防篡改 | 专门用于性能测量,浏览器会阻止恶意脚本修改其行为 |
二、与 Date.now()
的关键区别
// 使用 Date.now() console.log(Date.now()); // 返回从 1970-01-01 至今的毫秒数,受系统时间影响 // 使用 performance.now() console.log(performance.now()); // 返回从页面导航开始至今的毫秒数,精度更高
对比项 | performance.now() | Date.now() |
---|---|---|
精度 | 微秒级 (最高 5 微秒) | 毫秒级 |
时间参考点 | 页面导航开始时刻 | UNIX 纪元 (1970-01-01) |
是否受系统时间影响 | ❌ 不会 | ✅ 会 |
典型用途 | 性能分析、动画计时 | 普通时间记录 |
三、经典使用场景
1. 测量代码执行时间
const start = performance.now();
// 要测量的代码
for (let i = 0; i < 1000000; i++) {
Math.sqrt(i);
}
const end = performance.now();
console.log(`执行耗时: ${(end - start).toFixed(3)} 毫秒`);
2. 动画帧率计算
let lastFrameTime = performance.now();
function animate() {
const currentTime = performance.now();
const deltaTime = currentTime - lastFrameTime; // 计算帧间隔
console.log(`当前帧率: ${1000 / deltaTime} FPS`);
lastFrameTime = currentTime;
requestAnimationFrame(animate);
}
animate();
// 创建一个 img 元素,用于在页面上显示图片
const img = document.createElement('img');
// 初始化一个变量 index,用于记录当前要显示的图片的序号,初始值为 1
let index = 1;
// 设置 img 元素的 src 属性,动态拼接图片的路径,加载序号为 index 的图片
img.src = `/src/assets/running/${index}.png`;
// 设置 img 元素的宽度为 400 像素
img.width = 400;
// 设置 img 元素的高度为 400 像素
img.height = 400;
// 将创建好的 img 元素添加到页面的 body 元素中,使其在页面上显示
document.body.appendChild(img);
// 定义动画的帧率为 30 帧每秒
let fps = 30;
// 声明一个变量 rafObj,用于存储 requestAnimationFrame 返回的请求 ID,后续用于取消动画
let rafObj;
// 使用 performance.now() 获取当前的时间戳,并赋值给 lastTime 变量,作为动画的起始时间
let lastTime = performance.now();
// 定义一个名为 animation 的函数,用于实现动画效果
const animation = () => {
// 获取当前的时间戳
let now = performance.now();
// 计算当前时间与上一次更新图片的时间间隔,如果间隔大于 1000/fps(即每帧的时间间隔),则更新图片
if (now - lastTime > 1000 / fps) {
// 更新 lastTime 为当前时间,记录本次更新图片的时间
lastTime = now;
// 图片序号加 1,准备显示下一张图片
index++;
// 更新 img 元素的 src 属性,加载新序号对应的图片
img.src = `/src/assets/running/${index}.png`;
// 如果图片序号超过 12,将序号重置为 1,实现循环播放图片的效果
if (index > 12) {
index = 1;
}
}
// 使用 requestAnimationFrame 方法请求下一帧动画,传入 animation 函数作为回调,形成动画循环
rafObj = requestAnimationFrame(animation);
};
// 调用 animation 函数,启动动画
animation();
// 创建一个 button 元素,用于停止动画
const btn = document.createElement('button');
// 设置按钮的 id 为 'cancel'
btn.id = 'cancel';
// 设置按钮的显示文本为 '清除动画'
btn.textContent = '清除动画';
// 为按钮添加点击事件处理函数
btn.onclick = () => {
// 使用 cancelAnimationFrame 方法取消之前通过 requestAnimationFrame 请求的动画,传入 rafObj 作为请求 ID
window.cancelAnimationFrame(rafObj);
// 将 rafObj 置为 null,释放资源
rafObj = null;
};
// 将创建好的按钮添加到页面的 body 元素中,使其在页面上显示
document.body.appendChild(btn);
3. 性能基准测试
function benchmark(func) {
const start = performance.now();
func();
const duration = performance.now() - start;
return duration;
}
四、注意事项
-
跨域安全限制
某些浏览器(如 Firefox)在跨域 iframe 中会降低精度以防止时序攻击 -
隐私保护模式
在浏览器的隐私模式(如 Chrome 无痕模式)下可能降低精度 -
Worker 支持
在 Web Worker 中也可使用,但起始时间与主线程不同步 -
数值类型
返回值为DOMHighResTimeStamp
类型(实际上是double
)
五、兼容性
浏览器 | 支持版本 |
---|---|
Chrome | 6+ |
Firefox | 7+ |
Safari | 8+ |
Edge | 12+ |
Node.js | 8.5+ (需通过 require('perf_hooks').performance ) |
六、为什么需要高精度计时?
在以下场景中微秒级精度至关重要:
-
VR/WebGL 应用的帧同步
-
音频视频同步处理
-
高频交易系统
-
物理引擎计算
通过 performance.now()
开发者可以更精准地分析代码性能瓶颈。