Updated: Your browser might silently change setTimeout(f, 0) to setTimeout(f, 4)

Posted . Visible to the public. Auto-destruct in 24 days

Added a reference to a similar behavior when chrome is deliberately slowing down the setInterval and setTimeout rate Show archive.org snapshot

Changes

  • 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](http://caniuse.com/#feat=promises)) uses [microtasks](https://makandracards.com/makandra/40978-tasks-microtasks-queues-and-schedules-jakearchibald-com) and is thus not subject to timeout clamping.
  • If you need short nested timeouts, you can use an [setImmediate](https://github.com/YuzuJS/setImmediate) polyfill. This employs various hacks to give you access to the microtask queue.
  • Measuring timeout clamping
  • --------------------------
  • Here is a deeply nested `setTimeout` call:
  • ```js
  • 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:
  • ```raw
  • 2
  • 3
  • 5
  • 6
  • 11
  • 16
  • 20
  • 25
  • 29
  • 33
  • 38
  • ```
  • -Observe how after `6` the time difference jumps from 2 to 5 milliseconds.
  • +Observe how after `6` the time difference jumps from 2 to 5 milliseconds.
  • +
  • +
  • +
  • +## Timeouts are also clamped in background tabs
  • +
  • +On a similar note, all major browsers have implemented throttling rules for `setInterval` and `setTimeout` calls from tabs that are currently in the background. You can test it yourself by running this little test suite and change to a different tab during its runtime. The expected runtime drastically increases in Chrome, Firefox and Safari:
  • +<https://testbed.nicon.nl/timeouttest/>
  • +
  • +See also: [Stop animations and network polling when the document tab isn't visible](https://makandracards.com/makandra/41736-stop-animations-network-polling-document-tab-visible)
  • +
  • +
Michael Leimstädtner
Last edit
Michael Leimstädtner
License
Source code in this card is licensed under the MIT License.
Posted by Michael Leimstädtner to makandra dev (2024-09-09 11:04)