Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setInterval timing slowly drifts away from staying accurate

It seems that when I setInterval for 1000ms, it actually fires the function every 1001ms or so. This results in a slow temporal drift the longer its running.

var start; var f = function() {     if (!start) start = new Date().getTime();     var diff = new Date().getTime() - start;     var drift = diff % 1000;     $('<li>').text(drift + "ms").appendTo('#results'); };  setInterval(f, 1000); 

When run this shows the inaccuracy immediately.

  • 0ms
  • 1ms
  • 2ms
  • 3ms
  • 4ms
  • 5ms
  • 5ms
  • 7ms
  • 8ms
  • 9ms
  • 9ms
  • 10ms

See it for yourself: http://jsfiddle.net/zryNf/

So is there a more accurate way to keep time? or a way to make setInterval behave with more accuracy?

like image 571
Alex Wayne Avatar asked Nov 17 '11 20:11

Alex Wayne


People also ask

Why is setInterval not accurate?

The real-time interval can only be greater than or equal to the value we passed. From the above code, we can see that setInterval is always inaccurate. If time-consuming tasks are added to the code, the difference will become larger and larger ( setTimeout is the same).

How do I stop setTimeout interval?

The clearInterval() method clears a timer set with the setInterval() method.

Does setInterval affect performance?

This is unlikely to make much of a difference though, and as has been mentioned, using setInterval with long intervals (a second is big, 4ms is small) is unlikely to have any major effects.

Which is better setTimeout or setInterval?

setTimeout allows us to run a function once after the interval of time. setInterval allows us to run a function repeatedly, starting after the interval of time, then repeating continuously at that interval.


1 Answers

I think I may have figured out a solution. I figured, if you can measure it you can compensate for it, right?

http://jsfiddle.net/zryNf/9/

var start; var nextAt;  var f = function() {     if (!start) {         start = new Date().getTime();         nextAt = start;     }     nextAt += 1000;      var drift = (new Date().getTime() - start) % 1000;         $('<li>').text(drift + "ms").appendTo('#results');      setTimeout(f, nextAt - new Date().getTime()); };  f(); 

result varies a bit but here's a recent run:

0ms 7ms 2ms 1ms 1ms 1ms 2ms 1ms 1ms 1ms 

So if it gets called 1ms, 2ms or even 10ms later than it should the next call is scheduled to compensate for that. As long as inaccuracy is only per call, but the clock should never lose time, then this should work well.


And now I wrapped this up a global accurateInterval function which is a near drop in replacement for setInterval. https://gist.github.com/1d99b3cd81d610ac7351

like image 103
Alex Wayne Avatar answered Sep 18 '22 13:09

Alex Wayne