Есть ли риск, что setTimeout сработает дважды после того, как я его «перезагрузлю»? - PullRequest
1 голос
/ 29 сентября 2019

Иногда я использую следующую концепцию:

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. Тайм-аут срабатывает и обратный вызов выдвигается в EventLop, ожидая start(delay) дляend
  4. clearTimeout вызывается, но время ожидания уже выполнено
  5. start(delay) заканчивается и обратный вызов времени ожидания выполняется
  6. delay мс позже, обратный вызов времени ожидания выполняется снова

Возможно ли это? Если это возможно, как это предотвратить? Если это невозможно, что мешает этому случиться?

1 Ответ

2 голосов
/ 29 сентября 2019

Нет, это невозможно. clearTimeout удалит тайм-аут из очереди событий, если внутренний тайм-аут уже сработал. Он гарантирует, что обратный вызов не будет запущен после того, как вы вызвали clearTimeout.

В спецификации есть список активных таймеров , из которого осуществляется обратный вызовВыполнение извлекается заданием цикла событий по времени, и clearTimeout очищает таймер в этом списке, поэтому, даже если задача уже была запланирована, он по-прежнему будет проверять, активен ли таймер до выполнения обратного вызова.

...