最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Duration of setInterval - Stack Overflow

programmeradmin2浏览0评论

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

Here is fiddle - / 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>

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

Here is fiddle - https://jsfiddle/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

Share Improve this question edited Aug 12, 2016 at 21:27 T.J. Crowder 1.1m200 gold badges2k silver badges1.9k bronze badges asked Aug 12, 2016 at 21:24 HlushenokHlushenok 514 bronze badges 14
  • ++count? Is this valid JavaScript? – yuriy636 Commented Aug 12, 2016 at 21:26
  • 2 @yuriy636 yes - prefix increment – Rob M. Commented Aug 12, 2016 at 21:27
  • 2 Technically, the setTimeout/setInterval functions don't run something in exactly the timeout you give but rather schedule it to be run then. The difference is that since JS is single threaded, something else might be being processed already, so the timeout/interval-ed thing would be put on the queue – VLAZ Commented Aug 12, 2016 at 21:27
  • 1 @Miloshio querySelector does not return an HTML Collection, it returns a single DOM node. – Rob M. Commented Aug 12, 2016 at 21:31
  • 1 @T.J.Crowder I see, that's definitely short and accurate enough. Thanks for the tip, I'll make sure to spread the word :) – VLAZ Commented Aug 12, 2016 at 21:41
 |  Show 9 more ments

2 Answers 2

Reset to default 5

There's a minimum delay enforced by setTimeout and setInterval. From MDN

Reasons for delays longer than specified

Nested timeouts forced to >=4ms

Historically browsers implement setTimeout() "clamping": successive setTimeout() calls with delay smaller than the "minimum delay" limit are forced to use at least the minimum delay. The minimum delay, DOM_MIN_TIMEOUT_VALUE, is 4 ms (stored in a preference in Firefox: dom.min_timeout_value), with a DOM_CLAMP_TIMEOUT_NESTING_LEVEL of 5.

In fact, 4 ms is specified by the HTML5 spec and is consistent across browsers released in 2010 and onward. Prior to (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2), the minimum timeout value for nested timeouts was 10 ms.

So even though you're specifying 3000/2500 = 1.2 as the interval time, it's acting as if you'd used 4 as the interval time.

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>

发布评论

评论列表(0)

  1. 暂无评论