setTimeout 和 setInterval 坑

72 阅读1分钟

1.setTimeout的延迟是不确定的

delay 参数指定的是将回调函数添加到消息队列最小延迟时间 如果主线程繁忙,实际延迟大于等于dalay

2.setInterval可能导致任务堆积

直观比喻

想象一下:

  • 你有一个传送带(setInterval),每隔 1 秒放一个包裹(任务)。
  • 你是搬运工(JavaScript 主线程),每次搬一个包裹需要 2 秒。
  • 结果就是:包裹越来越多,堆积在传送带上。

举个例子:

setInterval(() => {
    console.log('start');
    // 模拟耗时任务
    const start = Date.now();
    while (Date.now() - start < 2000) {} //无限循环直到走出循环
    console.log('end');
}, 1000);

这里 setInterval 设置了 1 秒执行一次,但每次回调执行 2 秒。实际执行结果会是:

start
end
start
end
start
end
...
  • 你会发现“start”之间不会严格间隔 1 秒,而是因为任务在队列里堆积,可能连续执行。

3. 如何避免?

解决思路就是 不要让包裹堆积

  • 方法一:用 setTimeout 串行执行

    function runTask() {
      console.log("任务开始");
      setTimeout(runTask, 1000); // 完成后再等 1 秒
    }
    runTask();
    
  • 方法二:加锁/标志位,任务没完成就不开始下一个

    let running = false;
    
    setInterval(() => {
      if (running) return;
      running = true;
    
      console.log("任务开始");
      setTimeout(() => {
        console.log("任务结束");
        running = false;
      }, 2000);
    }, 1000);