Sometimes I use the following concept:
class ResetableTimeout extends EventEmitter {
constructor() {
this.id = -1;
}
start(delay) {
clearTimeout(this.id);
this.id = setTimeout(() =>{this.emit("done");}, delay);
}
}
Architecture like this may be used for throttling operations for example.
Now I noticed that this may fire twice under these circumstances:
setTimeout
starts timeoutstart(delay)
is called and is executingstart(delay)
to endclearTimeout
is called, but the timeout is done alreadystart(delay)
ends and timeout's callback executesdelay
ms later, timeout's callback executes againIs this possible? If it is possible how to prevent it? If it isn't possible, what prevents it from happening?
No, this is not possible. clearTimeout
will remove the timeout from the event queue if the internal timeout already had been fired. It assures that the callback will not run after you called clearTimeout
.
In the spec, there is a list of active timers, from which the callback to execute is fetched by the timed event loop task, and clearTimeout
clears the timer in that list so even when the task had already been scheduled it will still check whether the timer is still active before executing the callback.