16

n = 0;
var timer = setInterval(function() {
    if (n == 0) {
        console.log(new Date());
    }
    // execute some other code here
    n++;
    if (n == 1000) {
        clearInterval(timer);
        console.log(new Date());
    }
}, 1);

This code executes in about 3-4 seconds, depending on machine and browser maybe. How can I make it execute in exactly 1 second?

Boann
  • 48,794
  • 16
  • 117
  • 146
Jswq
  • 758
  • 1
  • 7
  • 23
  • 3
    The accuracy of the timer is different from system to system. You can't expect that the function will really be called once every ms. It may instead be called every few ms. – Tesseract Dec 25 '15 at 04:46
  • there is no loop in your code to de something 1000 times, or i'm blind. Also, it depends on your computers processor on how fast it can do an operation. – learningbyexample Dec 25 '15 at 04:51
  • Possible duplicate of [How do browsers determine what time setInterval should use?](http://stackoverflow.com/questions/11370522/how-do-browsers-determine-what-time-setinterval-should-use) – Bhojendra Rauniyar Dec 25 '15 at 04:55
  • 1
    Does it have to be exact 1 second? If you use straight loop, it may be less than 1 second. – Will Dec 25 '15 at 04:58
  • If you tell us what exactly you are trying to achieve we might be able to help you. There are many ways to get some code to run in 1s. – Tesseract Dec 25 '15 at 05:03
  • Please indent your code. –  Dec 25 '15 at 05:04
  • I just want to display a num increasingly many times in a second to act like the animation. and found it difficult to set the timer as a very low value in setInterval. Some I want to figure out the reason and learn from it! – Jswq Dec 25 '15 at 06:56
  • If you need this for an animation you could try [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) – Tesseract Dec 25 '15 at 07:16

3 Answers3

7

Javascript timers in browsers are inaccurate (C would be better for that usage).

However, you get a better averaged accuracy having the delay as high as possible, especially avoiding low values, like 1 ms.

It will be difficult to have 1000 evenly timed calls to a function, within one second. One millisecond being a low value , the simple execution of the triggered function itself (plus the overhead of handling timers) is likely to take a time close to 1 ms (or maybe more)... meaning the JS interpreter calls the function after 1ms, executes the code then set a new 1ms timer. Consequently there is more than 1ms between calls.

The JS interpreter does something like

At t   call function     <-- this takes
       execute function  <-- some 
at t+x set new 1ms timer <-- time
etc...

However if you can afford to end the process within a timeframe closer to 1 second (than the 3-4 seconds you have now), doing as many as possible 1 ms calls, this is possible.

var n = 0;

var timer= setInterval(function(){
          if(n++ == 0) {
                console.log(new Date());
          }
     }, 1);

setTimeout(function() {
         clearInterval(timer);
         console.log("Got n="+n+" at "+(new Date()));
     }, 1000);

This is basically the same program as yours

  • n is incremented every 1ms
  • however the end of the process is controlled by another 1-second timer

In Chrome, I get 252 n increments and the two dates are ~1 second apart.

Déjà vu
  • 28,223
  • 6
  • 72
  • 100
  • Thanks for answering me . according to your answer I write some code to test the delay of JS interpreter calling a function. it takes about 126ms in my chrome , and it far away from 3-4 seconds. So I think the problem is in the setInterval method. Could I use some kind of code like 'systtem.pause' to pause the JS interpreter for a very short time instead of using stInterval? – Jswq Dec 25 '15 at 06:38
  • var n=0; var startMs=new Date().getTime(); console.log(startMs); for (var i = 1000; i >= 0; i--) { testCallDelay(n); n++; } var endMs=new Date().getTime() console.log('after called 10000 times at:' + endMs); console.log('had been taken '+(endMs-startMs)+ ' ms'); function testCallDelay(n){ console.log(n); } //on the above is my code – Jswq Dec 25 '15 at 06:38
  • Do you really need 1ms intervals? Isn't ~250 calls per second enough? That will be difficult in JS. Using a loop to pause? 1) won't work consistently in your browser 2) in other browsers 3) if the script keeps eating CPU it may trigger a warning from the browser. See [this page](http://www.sitepoint.com/creating-accurate-timers-in-javascript/) but again, 1ms in JS is difficult... – Déjà vu Dec 25 '15 at 06:43
  • 1
    250 calls is enough for me right now~! I just want to figure out these problem in some kind of deep level. Thanks – Jswq Dec 25 '15 at 06:51
2

Here is a demonstration of the approach for one timer per iteration. It takes roughly 1 second to do 1000 "iterations" of the same callback. The design is rough as it is only an example.

jsFiddle Demo

//Function to compose the array of timers
function timers(count, callback){
  var timers = [];
  for(var i = 0; i < count; i++){
    timers.push(timer(callback,i));
  }
  return timers;
};
//Function to compose individual timer
function timer(callback, delay){
  return function(){
    setTimeout(callback,delay);
  };
};

//Usage
console.log("Start:",new Date()); //timestamp

var display = document.querySelector("#display");

var settings = { n : 0 };

display.innerHTML = settings.n;

//Arrange timers and callback
var set = timers(1000,function(){
    this.n++;
  display.innerHTML = this.n;
    if(this.n === 1000) console.log("End:",new Date());
}.bind(settings));

//Execute timers
for(var i = 0; i < set.length; i++){ set[i](); }
<div id="display">
</div>

All browsers handle this differently. In most browsers, especially chrome, the default smallest amount of time possible for a task to execute (as in using an interval or timeout) is 4 milliseconds.

The result of the 4ms window is that your 1000 iterations are being done in about 4 seconds. So, clearly this is longer than the desired 1 second in 1000 iterations.

There is not a desirable (possible?) way to accomplish an exact 1 millisecond iteration in JavaScript when executed in a modern browser. The best bet you would have if space (memory and processing power) were not an issue would be to create a timer for each iteration manually and then execute the entire set of them. This of course has its own issues, such as whether or not each task is even executed at the time it was supposed to.

Travis J
  • 81,153
  • 41
  • 202
  • 273
  • Alsome , Thanks, How can I calculate the space a set with function? Is not just simple like some kind of base type – Jswq Dec 29 '15 at 07:35
  • @Jack - It just depends on how much content you are working with. As long as it isn't being created too heavily each time you do this, it shouldn't be bad at all. If you need to do this on a large scale you would probably want to be more inclined to use an approach which took advantage of the garbage collector (by loosing scope quickly). – Travis J Dec 29 '15 at 09:30
0

Try the same script in ECMA Script 6

'use strict';

var n = 0;

var timer = setInterval(() => { 
    n++;
}, 1);
console.log( new Date() );

setTimeout(() => {
 clearInterval(timer);
 console.log("Final N Value: "+n+" at "+ (new Date()) );
}, 1000);
Venkat.R
  • 7,420
  • 5
  • 42
  • 63