Javascript is a language full of surprises: there are the good parts
and the bad parts
. Today, I discovered that setTimeout
featured a minimal delay of 4 msec.
This is well documented in Reasons for delays longer than specified.
But I wonder, how many experienced javascript developers are aware of this weird behaviour.
What about you?
Did you know that the minimal delay of setTimeout
was 4 msec?
In this article, we are going to:
- demonstrate the 4 sec delay added by the browser when one uses a
setTimeout
with 0 delay. - demonstrate how to write 0-delay timers using
postMessage
.
Code example
All the code snippets of this page are live and interactive powered by the klipse plugin:
- Live: The code is executed in your browser
- Interactive: You can modify the code and it is evaluated after 3 seconds of inactivity of if you press
Ctrl-Enter
inside the code snippet.
The 4 msec delay in action
Here is the code that demonstrates the 4-msec delay - calling setTimeout
recursively 100 times with a 0
delay.
As you can see by yourslef, the execution time for 100 iterations is around 400 msec.
You might need to reevaluate the snippet - for some reason the first evaluation takes much more time.
Press Ctrl-Enter
inside the code snippet or modify the code and wait for 3 seconds…
function bar(iterations) {
if(iterations === 0) {
console.log("done in: " + (new Date() - startTimeout)+ " msec")
}
else {
setTimeout(bar, 0, iterations - 1);
}
}
startTimeout = new Date();
console.log("Start");
bar(100);
Amazing. No?
The solution for fast timeouts
If we want to have a 0 msec
timer, we have to use postMessage
.
So, let’s do it and take the following code from setTimeout with a shorter delay.
setZeroTimeout
takes a single argument: the callback function that is going to be called with 0 delay - but asynchronously.
(function() {
var timeouts = [];
var messageName = "zero-timeout-message";
function setZeroTimeout(fn) {
timeouts.push(fn);
window.postMessage(messageName, "*");
}
function handleMessage(event) {
if (event.source == window && event.data == messageName) {
event.stopPropagation();
if (timeouts.length > 0) {
var fn = timeouts.shift();
fn();
}
}
}
window.addEventListener("message", handleMessage, true);
window.setZeroTimeout = setZeroTimeout;
})();
And now, let’s see it in action - in my browser, it takes around 17 msec for 100 iterations.
Again, you might need to reevaluate the snippet - as the first evaluation takes much more time.
Press Ctrl-Enter
inside the code snippet or modify the code and wait for 3 seconds…
function runBaz(iterations) {
function baz() {
if(--iterations === 0) {
console.log("done in: " + (new Date() - startZeroTimeout) + " msec")
}
else {
setZeroTimeout(baz);
}
}
baz();
}
startZeroTimeout = new Date();
console.log("OK");
runBaz(100);
By the way, what do you think about the interactive code snippets powered by KLIPSE?
You might what to give a star on Github…