Every JavaScript programmers should know that the setTimeout and setInterval invoked with a small number in their second argument would not be called in that time.
So the below script would not alert 0, but some number between 5 to 15 (in the unit of ms).
var startTime = new Date;
setTimeout(function() {
alert( new Date - startTime );
}, 0);
@bcherry
wrote a script to test this latency time.
As far as I ran the test on Mac OS X, Opera, Firefox and Safari all return around 10 ms, and Chromium returns about 4.5 ms.
Now, this latency is not big for usual use cases. When we write an animation in JavaScript, we usually pass a number between 30 and 50 to setTimeout/setInterval. That's around the number that something is apparently moving smoothly to the human eye.
But there are times we want as small time interval as possible, for example, when you run a terribly heavy loop and want to split the process into many asynchronous processes. The advantage of doing that is so that the browser's main process does not stop.
JSDeferred has it's example in the
sample page (look at the brainfuck interpreter example). When doing this kind of thing, length of the time out is crucial to the performance.
What JSDeferred does in order to overcome a minimum time interval is to use asynchronous DOM interfaces. In short, here is more or less how it's done.
function async(callback) {
var img = new Image;
img.addEventListener('error', callback, false);
img.src = 'data:,';
}
It's that simple. This code unfortunately doesn't work in IE, so it's slightly more complecated.
function async(callback) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "javascript:";
script.onreadystatechange = function () {
document.body.removeChild(script);
callback();
}
document.body.appendChild(script);
}
I tested performance using @bcherry's script, but changing setTimeout(fn, 0); to async(fn); with the async function I defined above. The average latency was about 0.16 ms on Chrome, 0.64 ms on Safari, 0.53 ms on Firefox, 0.059 ms on Opera 10.10 (wow!), and 0.52 ms on Opera 10.50 (degraded from 10.10...).
So, my async() is an order faster than setTimeout().
That there are other ways to implement the async() function, these apparently are not as universal as capturing img.onerror. Here is an example.
function async(callback) {
var script = document.createElement('script');
script.onload = function() {
document.body.removeChild(script);
callback();
}
script.src = 'data:,';
document.body.appendChild(script);
}
This takes 0.14 ms on Safari (notably faster than the above), 0.48 ms on Chromium, 0.50 ms on Firefox, but doesn't work on Opera.
Another one is this.
function async(callback) {
var xhr = new XMLHttpRequest;
xhr.open('GET','data:text/html,<html>',true);
xhr.onreadystatechange = function() {
xhr.onreadystatechange = null;
callback();
};
xhr.send(null);
}
This takes only 0.076 ms on Opera (both 10.10 and 10.50), and 0.64 ms on Safari. On Chromium and Firefox, it raises an error.
In conclusion, setTimeout is slow. Use other async APIs when performance is crucial.