When you're nesting setTimeout(f, 0)
calls, your browser will silently increase the delay to 5 milliseconds after the fourth level of nesting. This is called "timeout clamping".
Deeply nested setTimeout
can happen when you're using a non-native Promise
polyfill with long chains of then
calls.
The native Promise
implementation (
Can I use link
Show archive.org snapshot
) uses microtasks and is thus not subject to timeout clamping.
If you need short nested timeouts, you can use an setImmediate Show archive.org snapshot polyfill. This employs various hacks to give you access to the microtask queue.
Here is a deeply nested setTimeout
call:
var start = Date.now();
function printElapsed() {
var now = Date.now();
console.log(now - start);
}
setTimeout(function() {
printElapsed();
setTimeout(function() {
printElapsed();
setTimeout(function() {
printElapsed();
setTimeout(function() {
printElapsed();
setTimeout(function() {
printElapsed();
setTimeout(function() {
printElapsed();
setTimeout(function() {
printElapsed();
setTimeout(function() {
printElapsed();
setTimeout(function() {
printElapsed();
setTimeout(function() {
printElapsed();
setTimeout(function() {
printElapsed();
}, 0);
}, 0);
}, 0);
}, 0);
}, 0);
}, 0);
}, 0);
}, 0);
}, 0);
}, 0);
}, 0);
This yields the following messages:
2
3
5
6
11
16
20
25
29
33
38
Observe how after 6
the time difference jumps from 2 to 5 milliseconds.