在我“重置” setTimeout之后,setTimeout是否会触发两次?

时间:2019-09-29 15:24:15

标签: javascript settimeout race-condition

有时我使用以下概念:

class ResetableTimeout extends EventEmitter {
  constructor() {
    this.id = -1;
  }
  start(delay) {
    clearTimeout(this.id);
    this.id = setTimeout(() =>{this.emit("done");}, delay);
  }
}

例如这样的架构可以用于节流操作。

现在我注意到在这种情况下可能会触发两次:

  1. setTimeout开始超时
  2. start(delay)被调用并正在执行
  3. 超时触发并且回调被推入eventloop中,等待start(delay)结束
  4. clearTimeout被调用,但是超时已经完成
  5. start(delay)结束并且超时的回调执行
  6. delay毫秒后,超时的回调再次执行

这可能吗?如果有可能怎么预防呢?如果不可能,是什么阻止了它的发生?

1 个答案:

答案 0 :(得分:2)

否,这是不可能的。如果内部超时已经触发,clearTimeout将从事件队列中删除超时。这样可以确保在调用clearTimeout之后,回调不会运行。

In the spec,有一个活动计时器的列表,定时事件循环任务从中获取要执行的回调,而clearTimeout清除计时器列出,因此即使已安排任务,它仍将在执行回调之前检查计时器是否仍处于活动状态。