0

Please see the following JavaScript code:

var cis_current_time = 0;

setInterval(function() {
    cis_current_time += 1;
},1);

$("#timingInfo").html(cis_current_time);
setTimeout(function() {
    $("#timingInfo").html($("#timingInfo").html() + ', ' + cis_current_time);
},1000);

As a result I except to get 0, 1000, but it returns 0, number near 200

Please check a fiddle.

What is the reason of such behavior?

Simon
  • 22,637
  • 36
  • 92
  • 121
  • setInterval is not precise – Jaromanda X Jul 06 '15 at 14:27
  • Already answered before. `setTimeout` and `setInterval` have a minimal precision of 4~5 ms I believe (because it actually says "_after the current functions_, in approximately n milliseconds"), so you won't get it to run each millisecond. It has already been shown on SO, but where... – Kyll Jul 06 '15 at 14:28
  • 1
    as well as being imprecise, they are only guaranteed minimums. They really mean "run this code [repeatedly] sometime after x milliseconds" – James Thorpe Jul 06 '15 at 14:28
  • 3
    You can't guarantee they will be called regularly at all, no. If someone moves to another tab, browsers can and do throttle calls to `setInterval` callbacks. If you need to do things based on time passing, you need to use `Date` objects or `window.performance.now()`, recording the interval since your callback was last called. – James Thorpe Jul 06 '15 at 14:32

2 Answers2

1

setInterval and setTimeout may not be precise due to their design.

They are executed by the browser engine, which means the browser can throttle them in some cases. Just for an example, if your browser just uses one process for the JavaScript, they can be throttled or maybe elapse more ticks than you define, due to current pressure on your used core.

It can be improved a bit by using a multithreaded JavaScript, but anyway - they won't be 100% accurate.

setInterval only guarantees a new execution/call after the given time period. Not at the exact time. There may be differences each interval at all.

Ionic
  • 3,884
  • 1
  • 12
  • 33
0

setInterval function is very precise, as you can see on this fiddle.

Problem is in your code, you are trying to execute a function each milliseconds.

setInterval(function() {
    cis_current_time += 1;
},1);

JavaScript is monothreaded, then, when it has a lot of instructions, it stacks them and call them when it has the possibility, so, that's why it is not precise in your case.

setInterval is not the problem, JavaScript is : JS executes functions when it can, that's why it is executed later... Every function is concerned by this problem, so setInterval too...

Func(1) taking 70ms :

enter image description here

If Func(1) is taking 130ms :

enter image description here

setInterval is precise but has the same problem than each function in JS.

Image credits

Jacques Cornat
  • 1,612
  • 1
  • 19
  • 34
  • Try switching to another tab as soon as you run that fiddle, then switch back. [It is in no way precise](http://imgur.com/lmVTQkp). – James Thorpe Jul 06 '15 at 14:39
  • Yes here is an example output: `30s 990ms, 32s 539m` 1,5 Seconds difference! – Ionic Jul 06 '15 at 14:41
  • setInterval is **not** the problem, JavaScript **is** : it executes functions when it can, that's why it is executed later... **Every function is concerned by this problem, so setInterval too**... setInterval makes well its job when JavaScript is running usually ^^ That is what I'm thinking – Jacques Cornat Jul 06 '15 at 14:45
  • In this case, `setInterval` _is_ the problem. If you're using a machine where calling a function that increments a variable takes longer than 1 millisecond... well, I'd be _very_ surprised. – James Thorpe Jul 06 '15 at 14:47
  • Well, you are going to be surprised by this ^^ : [image](http://image.noelshack.com/fichiers/2015/28/1436194479-103.png) If you want to try : [jsfiddle](https://jsfiddle.net/qLme684k/4/) (Click on "Run" multiple times and see your console) – Jacques Cornat Jul 06 '15 at 14:54
  • Well, in that you're doing a `console.log` and constructing a new `Date` object between the two times, so that's not really suprising. [Try this one](https://jsfiddle.net/bzwupg70/), where it's calling a function to increment a variable, as I said before. [Before (left)/after (right) times](http://imgur.com/RHgv52i) are identical. – James Thorpe Jul 06 '15 at 15:15
  • Also note that [the actual spec](https://html.spec.whatwg.org/multipage/webappapis.html#timers) on timers (ie `setInterval` and `setTimeout`) says _"This API does not guarantee that timers will run exactly on schedule. Delays due to CPU load, other tasks, etc, are to be expected."_ – James Thorpe Jul 06 '15 at 15:17
  • Yup, you are right, but in the code `setInterval(function() { cis_current_time += 1; },1);`, he is not only incrementing... He is adding a time listener, which is taking much time, isn't it ? – Jacques Cornat Jul 06 '15 at 15:17
  • No, there's only one call to `setInterval`. Beyond that, it's only the function that contains the increment that's running each time the interval elapses, and that interval is in no way accurate to 1ms intervals. – James Thorpe Jul 06 '15 at 15:19
  • setInterval is called once, but it is adding a time listener at each end of the function. As you said it before, a variable increment is less than 1 ms, so this is the listener which takes more than 1 ms to be executed. (Sorry, I add credits ^^) – Jacques Cornat Jul 06 '15 at 15:24
  • The only code running in javascript is the callback function. How it gets called is an implementation detail down in the javascript engine of the browsers/host being used. I would be surprised if they were registering a brand new event each time the last one runs, it's certainly not how I'd implement it. And this is going to be native code too, so it will be quick. The issue is simply that `setInterval` and `setTimeout` are not precise, and are not designed to be. – James Thorpe Jul 06 '15 at 15:40