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避免主线程阻塞
避免在计时器回调中执行耗时操作
网友回复