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

javascript - Is it safe to pass setInterval or setTimeout a fractional delay? - Stack Overflow

programmeradmin1浏览0评论

I know that the difference would currently be negligible due to inaccurate browser timers, but for the sake of knowledge if nothing else: is there any browser that supports setInterval and setTimeout, but requires that they be passed an integer value as a delay?

Or, rephrased with examples, is this:

setInterval(animate,50/3);

as cross-browser compatible as this?

setInterval(animate,17);

I know that the difference would currently be negligible due to inaccurate browser timers, but for the sake of knowledge if nothing else: is there any browser that supports setInterval and setTimeout, but requires that they be passed an integer value as a delay?

Or, rephrased with examples, is this:

setInterval(animate,50/3);

as cross-browser compatible as this?

setInterval(animate,17);
Share Improve this question asked Dec 12, 2011 at 0:51 user1000131user1000131 2
  • The way it's defined, the second argument is the "number of miliseconds". Now, if that number should be natural is not defined... – Šime Vidas Commented Dec 12, 2011 at 0:58
  • @ŠimeVidas It's perfectly defined. See the DOM specification ;-) – user166390 Commented Dec 12, 2011 at 1:36
Add a comment  | 

5 Answers 5

Reset to default 11

It is perfectly safe.

(As RobG points out, I haven't provide a reference to the DOM/JS bridge rules themselves and he urges caution. FWIW, I believe -- but have no reference to conclusively state -- that ToInteger is part of the interface bridge. Here is a jsfiddle showing the timeout being passed as a string, a float, and an integral (same type as float in JS) which works fine in FF8 and IE9. Feedback welcome.)

This is because the DOM interface only accepts integers for the delay in setTimeout/setInterval -- yup, these are defined in the DOM, not in ECMAScript. The delay value is appropriately converted to an integral value first (and in this aspect the [JS-internal] ToInteger function is invoked which performs a truncation*).

However, the example numbers will actually yield slightly different results (although it might not be noticable) :-)

This is because, 50/3 (16.66andsomemore -> 16) and 17 specify different timeouts.

Happy coding.


*ToInteger is defined as sign(number) * floor(abs(number)), excluding special cases. See Section 9.4 of the 5th Edition ECMAScript specification.

Javascript makes no real distinction between floating point numbers and integers, and are the same data type under the hood. 1 and 1.0 are bit for bit identical in memory.

Therefore yes, you can pass a fractional value without any real issues. It's perfectly valid JavaScript. And even if it did require an integer, it's more likely it would simply and silently round it down for you.

But don't expect it to be accurate! A time of 0.1, 1 or even 4.87 will all probably fire at very close to the same time due to the low granularity of the callback scheduling.

I would imagine that the second parameter would be evaluated as an expression and as long as it returns a number it will work. It seems to work in chrome. Just make sure you don't divide by zero!

These functions expect milliseconds. I doubt you could expect any accuracy greater than 10ms, and browsers enforce timer restrictions.

Firefox doesn't mind decimal values. You can test in any other browsers you're curious about.

It depends, depends on whether argument delay is converted to integer, whether cumulative-delay[^1] strategy is used, depends on whether you are using a battery-powered device and power saving mode is on.

Test setInterval with 1000/15~=66.6667 delay, 60s duration, keep page visible all the time (without switching to background, without screen off), with the following browsers:

  • Windows Chrome 108
  • Android Chrome 107
  • iOS Safari 16.0
  • Windows Firefox 107
  • Android Firefox 108 Beta

see CodePen setInterval actual interval test

Actual average interval tick of setInterval

occasion \ platform Windows Chrome Android Chrome macOS Safari iOS Safari Windows Firefox Android Firefox
page visible 66.01 66.01 66.69 78.45 66.67
page visible (battery power saving mode) 66.01 66.01 89.76 78.36 66.68
page hidden
page hidden (battery power saving mode)

According to the test result above, what I can tell is:

Chrome's setInterval will floor() argument delay, but it use self-calibration[^2] strategy to keep ticks in time, currently ignores Batter Saver Mode.

Safari's setInterval depends on state of Low Power Mode, it supports fractional delay and use self-calibration strategy to keep ticks in time, but if Low Power Mode is on then cumulative-delay effect happens such that a fractional delay just doesn't help.

Windows Firefox's setInterval uses cumulative-delay strategy,while Android Firefox's setInterval uses self-calibration strategy.

Footnote:

[^1]: cumulative-delay means average tick interval will be obviously larger than argument delay.

[^2]: self-calibration means average tick interval can be very close to argument delay.

发布评论

评论列表(0)

  1. 暂无评论