Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firefox invokes setTimeout function too soon (or Date.getTime() is off?)

I've run into a strange issue in Firefox 12. setTimeout() doesn't seem to always wait the appropriate length. Or perhaps it's the date's milliseconds that don't jive?

Check out this fiddle. Essentially, a setTimeout of 100ms seems to run anywhere between 80ms and 110ms. More I can understand, based on John Resig's explanation of timers. But less?

You may have to refresh it once or twice to see the issue, as it sometimes works correctly on the first run. It seems to work spifftacular in IE and Chrome.

Here's the code I'm using in my fiddle:

var txt = '',
    TIMEOUT_LENGTH = 100,
    _now;

now = Date.now || function() { return new Date().getTime() };

function log(time) {
    c = time < 100? 'class="error"' : '';
    $('#log').append('<p '+c+'>waited ' + time + '</p>');
}

function defer() {
    var d = $.Deferred(),
        start = now();
    setTimeout(function() {
        d.resolve(now() - start);
    }, TIMEOUT_LENGTH);
    return d.promise();
}

for (var i = 0; i < 20; i++) {
    defer().then(log);
}

Here's a sample of the quirky output:

enter image description here

Here's my browser info:

enter image description here

And thanks so much for reading my question! I hope someone can shed some light into this.

MORE INFO

I worked around the problem by using setInterval() and checking each increment to see if the required time has passed. See this fiddle.

However, I'm still very interested to hear if anyone can shed some light into the source of the issue

like image 200
Kato Avatar asked Jun 04 '12 01:06

Kato


People also ask

Why is the setTimeout () function used?

setTimeout() The global setTimeout() method sets a timer which executes a function or specified piece of code once the timer expires.

What can I use instead of setTimeout?

The setTimeout() is executed only once. If you need repeated executions, use setInterval() instead. Use the clearTimeout() method to prevent the function from starting.

Is setTimeout a blocking call?

Explanation: setTimeout() is non-blocking which means it will run when the statements outside of it have executed and then after one second it will execute. All other statements that are not part of setTimeout() are blocking which means no other statement will execute before the current statement finishes.

How do you wait for setTimeout to finish?

Use of setTimeout() function: In order to wait for a promise to finish before returning the variable, the function can be set with setTimeout(), so that the function waits for a few milliseconds. Use of async or await() function: This method can be used if the exact time required in setTimeout() cannot be specified.


2 Answers

Yes. setTimeout's accuracy is based off many factors, and isn't guaranteed to always execute at the exact time you specify.

I cannot say this with any authority, but I'll hazard a guess that Firefox, in an attempt to seem faster, will speed up the JS engine temporarily to get everything in motion (which is interesting, because in my experience, timer-based functions actually run slower at first initially in my version of firefox).

Neither setTimeout nor setInterval promise that they will execute at the exact right time, as the link you posted stated. However, with setInterval, you get the benefit of the timer loop doing what it can to "correct itself" by catching up if it lags too far behind, so for whatever you're trying to do, it may be more appropriate.

Anyway, here's my results on my Macbook 10.6.8:

Firefox 5.0.1:

waited 92
waited 92
waited 93
waited 93
waited 93
waited 93
waited 93
waited 94
waited 93
waited 93
waited 93
waited 93
waited 94
waited 94
waited 94
waited 94
waited 94
waited 95
waited 96
waited 96

Safari 5.1.5:

waited 100
waited 104
waited 104
waited 103
waited 104
waited 104
waited 104
waited 104
waited 104
waited 104
waited 104
waited 104
waited 104
waited 104
waited 104
waited 104
waited 104
waited 104
waited 104
waited 104

Chrome 19.0.1084.52:

waited 101
waited 103
waited 103
waited 104
waited 104
waited 103
waited 103
waited 103
waited 103
waited 103
waited 103
waited 103
waited 103
waited 103
waited 104
waited 104
waited 104
waited 104
waited 104
waited 104
like image 71
Jeffrey Sweeney Avatar answered Oct 11 '22 18:10

Jeffrey Sweeney


JavaScript is synchronous. The browser will add your setTimeouts to the queue and execute them after

  1. The countdown is over
  2. It has finished any other tasks that are in the queue at the moment the countdown is over.
like image 28
user2428118 Avatar answered Oct 11 '22 20:10

user2428118