Hlushenok Hlushenok - 3 months ago 21
Javascript Question

Duration of setInterval

I created a simple function which counting value from 0 to some value during 3 sec.


Here is fiddle - https://jsfiddle.net/ar6akv5z/ and snippet:



var number = document.querySelector('.number');
var button = document.querySelector('button');

button.addEventListener('click', function() {
counting(number, 2500);
})

function counting(elem, value) {
var count = 0;
var timerId = setInterval(function() {
if (++count == value) clearInterval(timerId);
elem.innerHTML = count;
}, 3000/value);
}

<span class="number">0</span>
<button>Go</button>





But the duration of the function takes longer than 3 seconds.
Can you explain me why it is happend or show me my mistake.

Thanks and sorry for my english

Answer

The minimum interval of a timer is subject to an algorithm specified is the HTML5 spec (originally it was in the now-defunct timers spec), to keep timers from firing too rapidly. When a timer schedules a timer (which is essentially what setInterval does), once the nesting reaches five, if the timer interval requested is < 4ms, it's set to 4ms:

  1. If nesting level is greater than 5, and timeout is less than 4, then increase timeout to 4.

Since you're telling it to count up by 1 each time the timer fires, and it quite quickly starts only firing every 4ms (at best), it takes 4 * 2500 = 10000ms (10 seconds) to finish.

You can see this average delay in the updated snippet below, which replaces the counter with the average time between callbacks:

if (!Date.now) {
  Date.now = function() {
    return +new Date();
  };
}
var number = document.querySelector('.number');
var button = document.querySelector('button');
var sum = 0;
var last = null;

button.addEventListener('click', function() {
    counting(number, 2500);
})

function counting(elem, value) {
 var count = 0;
  last = Date.now();
 var timerId = setInterval(function() {
   var now = Date.now();
   sum += now - last;
   last = now;
  if (++count == value) clearInterval(timerId);
  elem.innerHTML = sum / count;
 }, 3000/value);
}
<span class="number">0</span>
<button>Go</button>