55

I would like to put

var minValue = 0;
if ( typeof callback == 'function' ) {
    setTimeout( callback, minValue );
}

this code when I implement callback function with JavaScript.

But I've found that modern browsers and some old browsers

have different minimum timeout value.

I know that Zero cannot be minimum value.

What would be minimum value of setTimeout for

modern browsers and some old browsers for compatibility issues?

jwchang
  • 10,584
  • 15
  • 58
  • 89

4 Answers4

52

I think that 10 will be the most reliable minimum in all browser, since I've seen a lot of codes using it.

However, 4ms is the minimum for HTML5

In fact, 4ms is specified by the HTML5 spec and is consistent across browsers released in 2010 and onward. Prior to (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2) , the minimum timeout value for nested timeouts was 10 ms.

Martin.
  • 10,494
  • 3
  • 42
  • 68
  • 3
    I´m sorry, this is not (no longer?) true. I just cannot find a statement about a 4ms delay in the [standard](http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#timers), except for a note: "Note: Timers can be nested; after five such nested timers, however, the interval is forced to be at least four milliseconds." Further curiosity led me to [this great post](https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/Hn3GxRLXmR0/XP9xcY_gBPQJ) on google groups about how they do it in Chrome. – Tobbe Brolin Dec 10 '13 at 21:22
  • @TobbeBrolin Whether it's true in implementation, [it is still in the spec](http://www.w3.org/TR/html5/webappapis.html#timers): "If the currently running task is a task that was created by the setTimeout() method, and timeout is less than 4, then increase timeout to 4." – apsillers Jan 15 '14 at 02:29
  • 3
    @TobbeBrolin However, I don't see that langauge reflected in WHATWG's spec. Looks like the W3C and WHATWG disagree on this. – apsillers Jan 15 '14 at 12:59
  • 1
    so if nested level is less than five, the lowest value is "1 ms" in Chrome https://chromium.googlesource.com/chromium/blink/+/master/Source/core/frame/DOMTimer.cpp#93 – twxia Aug 18 '19 at 15:41
11

The minimum is 4ms (as of HTML5) in modern browser, prior to that, it was 10ms. Note that these times are never 100% accurate.

Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308
  • 2
    4ms delay is only for when the call is made from 5 nesting levels. – Kaiido Jul 10 '20 at 04:58
  • @Kaiido but how practice shows, you will never get timeout equal to 4ms, it will be about 5ms – MaximPro Sep 19 '21 at 23:22
  • @MaximPro not sure to understand your comment. The point of mine was that contrarily to what this answer states, there is no minimum timeout restriction for timeouts that are not at least at 5th nesting level. So `onclick=e=>setTimeout(fn,0)` will execute fn in less than 4ms if nothing else blocks the browser. (There were a 1ms minimum in Chrome but they removed it) – Kaiido Sep 20 '21 at 02:23
  • @Kaiido I just emphasized that timeout between nested timers (that will be nested 5 and more times) will be approximately about 5ms, that's it. – MaximPro Sep 20 '21 at 11:35
5

New Version

There is no guaranteed delay. Scheduling mechanics, including the minimum amount of milliseconds of setTimeout, depend on your JavaScript environment and/or your OS, since they are not in the official ECMA specs.

JavaScript engines generally have multiple queues that the event queue continually processes. Once the current script has finished executing (e.g. the one that calls setTimeout(someCallback)), the loop will look through all queues, in order of priority, and execute all pending requests that are due (including someCallback, or any other callback to a setTimeout/setImmediate/process.nextTick etc. call).

Once the loop finishes an iteration, modern implementations set it up to wait for the least amount of time necessary until the next event is due, or until an external IO event wakes it up. E.g. if you have three active setTimeout timers, it will wait for the min of the remaining time on those three timers.

Warning: Depending on queue priority, the granularity of this might vary. Note that high-resolution system timers are expensive. So if you schedule something for a low-priority queue, or the schedule time itself is high, they might opt to use a lower performance timer for the "wake-up call", meaning, things might vary a lot between different queues and delays. Also, as my tests show, Chrome does not care, and uses (quite) a high-resolution timer even for setTimeout, (apparently).

Here are some tests I just quickly ran in Chrome and Node on Windows 10.

Code:

function testScheduler(scheduler, ms) {
  function f() {
    console.log(`${scheduler.name} with ${ms ? `${ms} ms` : 'no'} delay:`, performance.now() - s);
  }
  var s = performance.now();
  scheduler(f, ms);
}

testScheduler(setTimeout, 0);
testScheduler(setTimeout, 1);
testScheduler(setTimeout, 5);
testScheduler(setTimeout, 100);
testScheduler(setImmediate);

Experiment Results:

Summary of results:

  1. Numbers can vary wildly.
  2. Node is less accurate than Chrome (despite using the same engine (V8) under the hood).

Chrome (2022/9):

(NOTE: in Chrome, setImmediate was removed.)

setTimeout with 0 ms delay: 0.19999998807907104
setTimeout with 1 ms delay: 1.9000000357627869
setTimeout with 5 ms delay: 6.900000035762787
setTimeout with 100 ms delay: 110.5

Node@16 (some run):

setImmediate with no delay: 0.23650002479553223
setTimeout with no delay: 5.476700007915497
setTimeout with 1 ms delay: 5.6164000034332275
setTimeout with 5 ms delay: 6.091899991035461
setTimeout with 100 ms delay: 103.40990000963211

Node@16 (some other run):

setImmediate with no delay: 1.2796000242233276
setTimeout with no delay: 19.26560002565384
setTimeout with 1 ms delay: 19.923299968242645
setTimeout with 5 ms delay: 21.00239998102188
setTimeout with 100 ms delay: 107.54070001840591

System Timers

When the queue does not run right away, and when idling between iterations, then the minimum amount of milliseconds is determined by the timeslice resolution of your operating system and hardware. The smallest "sleepable" amount of time is usually the time it takes for the process to be allocated another timeslice by your system's scheduling algorithm.

On Windows (post XP) for example, Node might be using Windows' sleep system call, for this, while the results for Chrome seem to indicate that it uses a higher resolution timer than this.

Domi
  • 22,151
  • 15
  • 92
  • 122
  • 7
    I must admit this answer does not convince me, as it doesn't match with what I think I know about javascirpt (mostly-)single-threaded event-based execution. Could you point to any reference saying that any js implementation calls `sleep`? – Davide Dec 11 '15 at 10:35
  • 2
    *"it might continue immediately, depending on how your Javascript run-time is implemented"* - If the runtime is implemented correctly the timeout won't run until after the current code finishes executing - even if you specify a time of 0 it will still queue. – nnnnnn Jul 20 '16 at 14:17
  • 2
    I highly doubt it. Specially `sleep`|`Sleep` system calls being involved with this. I suppose javascript has it's own scheduling mechanism and the granularity will ultimately depend on the particular browser implementation of the language. But javascript is event based and I think it would be checking for events in a loop and if there are any scheduled and "*expired*" execute them. That's why it's not accurate (milliseconds are large in this context, so accuracy should be expected) and also why there should be a limit for `setTimeout()`'s time parameter. – Iharob Al Asimi Sep 30 '18 at 20:12
  • @Davide I finally got around to re-write it – Domi Sep 29 '22 at 20:36
3

This article tests Firefox, Safari, and Opera and plots performance graphs:

http://ejohn.org/blog/analyzing-timer-performance/

Firefox 2, Opera, and Safari all have a bottom window of 10ms for delays

For older browsers, you can do a test like the one in that article. I just ran a test that I had from a while ago of setInterval using a 10ms interval in IE6, and I got an average of 55ms. setTimeout seems to be lower at 35ms.

I ran the test in Chromium and got ~11ms average for a 10ms timeout. I tried it with 4ms and 1ms intervals and got ~4.5ms for both. Also, keep in mind that the numbers could vary among operating systems.

If you're interested, here's the test code:

<script>
// number of times to call setTimeout before calculating average
var ITERATIONS = 200;

window.onload = function()
{
    testTimeout(10, +new Date, 0, 0);
}

// calls setTimeout repeatedly at a specified interval, tracking the amount
// of time that passes between successive calls
function testTimeout(interval, last, sum, ii)
{
    var time = +new Date;
    var difference = time - last;
    sum += difference;
    if (ii % ITERATIONS == 1)
    {
        document.body.innerHTML = sum / ITERATIONS;
        sum = 0;
    }
    window.setTimeout(
        function() {
            testTimeout(interval, time, sum, ii + 1)
        }, interval);
}
</script>
0eggxactly
  • 4,642
  • 1
  • 16
  • 16