I need to generate an event exactly every 1s.
There is no way to do this with exact precision.
The time passed to setTimeout
is the minimum guaranteed time in which your code will run, not the exact time.
The time represents in how many milliseconds the JS Engine will push that function to the Event Queue. Once the function is in the Event Queue, it runs after all the current tasks present in the queue, such as events and other timers, which will create a delay.
Additionally, no task can be executed from the Event Queue while any regular JS code is running which could also potentially create small delays.
For example, this function test
:
setTimeout(function test() {
console.log('second');
}, 0);
for (i = 0; i < 1000000; i++); // the number 1000000 is an arbitrary big number
console.log('first');
Will run after the loop below it has finished, which will be more than 0
milliseconds away.
In fact, if that loop was infinite, the setTimeout
callback will never fire.
Note: As mentioned by nnnnnn in the comments, the actual minimum time, as per the HTML5 spec, in which setTimeout
will push a function to the Event Queue is 4ms, regardless if we put less. Previously that limit used to be 10ms.
MDN
In fact, 4 ms 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.