A.S.: This question is about the internals of how setTimeout
and setInterval
works, not about their typical usage.
When calling setTimeout
in a browser, it returns a timeout ID that you are then supposed to use in clearTimeout
. The timeout ID is an integer, and calling setTimeout
twice in a row results in IDs that are sequential (see the demo below).
const timeoutIds = []
// generate a bunch of timeouts for entropy
for (let i = 0; i <= Math.random() * 100; i += 1) {
setTimeout(() => {}, 0)
}
// generate two timeouts sequentially
timeoutIds.push(setTimeout(() => {}, 0))
timeoutIds.push(setTimeout(() => {}, 0))
// verify that they will always have sequential IDs
console.log({ timeoutIds })
console.assert(timeoutIds[1] === timeoutIds[0] + 1)
This suggests that there is a shared counter that is incremented every time setTimeout
is called.
Since there is a shared counter, and setTimeout
has an asynchronous side effect, this lead me thinking whether it is possible (at least, in principle) to break the counter and force it to issue a wrong timeout ID. Maybe, by passing a reference to the main thread’s setTimeout
to a worker, or something as dirty?
const timeoutId1 = scheduleTimeoutSomehow(() => console.log(42))
const timeoutId2 = scheduleTimeoutSomehow(() => console.log(17))
clearTimeout(timeoutId2)
// console logs '17' eventually, and never logs '42'