JS中的计时器(setTimeout/setInterval)并不精确,主要有以下原因:
JS是单线程的,计时器需要等待主线程空闲才能执行:
// 示例:实际间隔可能大于1000ms
setInterval(() => {
console.log('执行时间可能不准');
// 如果这里有耗时操作,会影响下一次执行时间
}, 1000); 最小延迟限制:浏览器通常限制最小延迟为4ms左右:
// 即使设置0ms,实际也会有约4ms延迟
setTimeout(() => {
console.log('有最小延迟');
}, 0); 更精确的计时方案:
使用Date或performance.now()计算实际时间差:
const start = performance.now();
const interval = 1000; // 目标间隔1秒
function accurateTimer() {
const drift = performance.now() - start - count * interval;
count++;
setTimeout(accurateTimer, interval - drift);
} 使用requestAnimationFrame实现高精度动画:
let lastTime = 0;
function animate(currentTime) {
if (currentTime - lastTime >= 16.7) { // 60fps
// 执行动画
lastTime = currentTime;
}
requestAnimationFrame(animate);
}
requestAnimationFrame(animate); Web Worker中的计时器:```javascript// worker.jslet count = 0;setInterval(() => {count++;postMessage(count);}, 1000);// main.jsconst worker = new Worker('worker.js');worker.onmessage = (e) => { console.log(e.data);};
5. 节流控制示例:
```javascript
function throttle(fn, interval) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= interval) {
fn.apply(this, args);
lastTime = now;
}
};
}
const throttled = throttle(() => {
console.log('执行');
}, 1000); 改进精度的建议:
使用performance.now()代替Date.now()获取更高精度时间戳
补偿误差:
class PreciseTimer {
constructor(callback, interval) {
this.callback = callback;
this.interval = interval;
this.expected = Date.now() + interval;
this.timeout = null;
this.start();
}
start() {
const drift = Date.now() - this.expected;
this.callback();
this.expected += this.interval;
this.timeout = setTimeout(() => this.start(),
Math.max(0, this.interval - drift));
}
stop() {
clearTimeout(this.timeout);
}
} 使用Web Worker避免主线程阻塞
避免在计时器回调中执行耗时操作
网友回复


