setTimeout会因为浏览器的事件循环机制导致计时器的误差,JS代码越复杂、越多,误差越大。
通过使用performance.now()可以一定程度上减小这个误差值。
performance.now()返回的是一个浮点数,表示从页面加载到现在的毫秒数,精度可以达到微秒级别
优化前的代码:
let a = 0;
function simpleTimeoutCounter() {
let sum = 0;
for (let i = 0; i < 100000000; i++) {
sum += Math.sqrt(i); // 模拟的复杂运算
}
a++;
console.log(`第${a}次打印`);
// 直接设置下一次执行时间为1000毫秒后
setTimeout(simpleTimeoutCounter, 1000);
}
// 启动计时器
simpleTimeoutCounter();
优化后的代码:
let startTime = performance.now();
const printTime = () => {
// 计算时间
const allTime = performance.now() - startTime;
let sum = 0;
for (let i = 0; i < 100000000; i++) {
sum += Math.sqrt(i); // 模拟的复杂运算
}
// 打印当前的执行时间(自开始以来的总时间)
console.log(`已过去 ${allTime.toFixed(2)} 毫秒`);
// 计算下一次执行应该在多少毫秒后,确保接近但不超过1秒的间隔
const nextTime = Math.max(0, 1000 - (allTime % 1000));
// 使用setTimeout安排下一次执行
setTimeout(printTime, nextTime);
};
// 启动计时器
printTime();
效果对比: