+
101
-

回答

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避免主线程阻塞

避免在计时器回调中执行耗时操作

网友回复

我知道答案,我要回答