setInterval with 0ms delays within Web Workers
Jan 24 2020 · Web Technologies
The 4ms minimum
Due to browser restrictions, you typically can’t have a setInterval
call where the delay is set to 0, from MDN:
In modern browsers, setTimeout()/setInterval() calls are throttled to a minimum of once every 4 ms when successive calls are triggered due to callback nesting (where the nesting level is at least a certain depth), or after certain number of successive intervals.
I confirmed this by testing with the following code in Chrome and Firefox windows:
setInterval(() => {
console.log(`now is ${Date.now()}`);
}, 0);
In Firefox 72:
In Chrome 79:
The delay isn’t exact, but you can see that it typically comes out to around 4ms, as expected. However, things are a little different with web workers.
The delay with web workers
To see the timing behavior within a web worker, I used the following code for the worker:
const printNow = function() {
console.log(`now is ${Date.now()}`);
};
setInterval(printNow, 0);
onmessage = function(_req) {
};
… and created it via const worker = new Worker('worker.js');
.
In Chrome, there’s no surprises, the behavior in the worker was similar to what it was in the window:
Things get interesting in Firefox:
Firefox starts grouping the log messages (the blue bubbles), as we get multiple calls to the function within the same millisecond. Firefox’s UI becomes unresponsive (which is weird and I didn’t expect as this is on an i7-4790K with 8 logical processors and there’s little interaction between the worker and the parent window), and there’s a very noticeable spike in CPU usage.
Takeaway
setInterval()
needs a delay and you shouldn’t depend on the browser to set something reasonable. It would be nice if setInterval(.., 0)
would tell the browser to execute as fast as reasonably possible, adjusting for UI responsiveness, power consumption, etc. but that’s clearly not happening here and as such it’s dangerous to have a call like this which may render the user’s browser unresponsive.