我想放置
var minValue = 0;
if ( typeof callback == 'function' ) {
setTimeout( callback, minValue );
}
在使用JavaScript实现回调函数时,我遇到了这段代码。
但我发现现代浏览器和一些老旧的浏览器具有不同的最小超时值。
我知道零不能是最小值。
为了兼容性问题,在现代浏览器和一些老旧的浏览器中setTimeout的最小值是多少?
我想放置
var minValue = 0;
if ( typeof callback == 'function' ) {
setTimeout( callback, minValue );
}
在使用JavaScript实现回调函数时,我遇到了这段代码。
但我发现现代浏览器和一些老旧的浏览器具有不同的最小超时值。
我知道零不能是最小值。
为了兼容性问题,在现代浏览器和一些老旧的浏览器中setTimeout的最小值是多少?
我认为10毫秒将成为所有浏览器中最可靠的最小值,因为我已经看到很多代码在使用它。
实际上,在2010年及以后发布的浏览器中,4毫秒已被HTML5规范指定,并且在各个浏览器之间保持一致。在此之前(Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2),嵌套超时的最小超时值为10毫秒。
最小时间为4毫秒(HTML5版本),在现代浏览器中,之前是10毫秒。请注意,这些时间永远不会100%准确。
onclick=e=>setTimeout(fn,0)
将在不到4ms的时间内执行fn。(在Chrome中有1ms的最小值,但他们已经删除了它) - Kaiido没有保证的延迟时间。调度机制,包括setTimeout
的最小毫秒数,取决于您的JavaScript环境和/或操作系统,因为它们不在官方ECMA规范中。
JavaScript引擎通常有多个队列,event queue不断处理。一旦当前脚本执行完毕(例如调用setTimeout(someCallback)
的脚本),循环将按优先级顺序查看所有队列,并执行所有到期的挂起请求(包括someCallback
或任何其他回调到setTimeout
/setImmediate
/process.nextTick
等调用)。
一旦循环完成一次迭代,现代实现会设置等待最少的时间,直到下一个事件到期,或者直到外部IO事件唤醒它。例如,如果您有三个活动的setTimeout
计时器,则它将等待这三个计时器上剩余时间的最小值。
警告:根据队列优先级,这可能会导致粒度变化。请注意,高分辨率系统计时器的成本很高。因此,如果您将某些内容安排到低优先级队列中,或者调度时间本身很长,则它们可能会选择使用较低性能的计时器进行“唤醒调用”,这意味着不同队列和延迟之间的情况可能会有很大差异。此外,正如我的测试所示,Chrome并不关心,并且即使在setTimeout
中也使用(相当)高分辨率计时器。
这是我刚在Windows 10上快速运行的一些Chrome和Node测试。
代码:
function testScheduler(scheduler, ms) {
function f() {
console.log(`${scheduler.name} with ${ms ? `${ms} ms` : 'no'} delay:`, performance.now() - s);
}
var s = performance.now();
scheduler(f, ms);
}
testScheduler(setTimeout, 0);
testScheduler(setTimeout, 1);
testScheduler(setTimeout, 5);
testScheduler(setTimeout, 100);
testScheduler(setImmediate);
结果概述:
Chrome(2022/9):
(注意:在 Chrome 中,setImmediate
已被移除。)
setTimeout with 0 ms delay: 0.19999998807907104
setTimeout with 1 ms delay: 1.9000000357627869
setTimeout with 5 ms delay: 6.900000035762787
setTimeout with 100 ms delay: 110.5
Node@16(某些运行):
setImmediate with no delay: 0.23650002479553223
setTimeout with no delay: 5.476700007915497
setTimeout with 1 ms delay: 5.6164000034332275
setTimeout with 5 ms delay: 6.091899991035461
setTimeout with 100 ms delay: 103.40990000963211
Node@16(其他一些运行):
setImmediate with no delay: 1.2796000242233276
setTimeout with no delay: 19.26560002565384
setTimeout with 1 ms delay: 19.923299968242645
setTimeout with 5 ms delay: 21.00239998102188
setTimeout with 100 ms delay: 107.54070001840591
当队列不会立即运行,并且在迭代之间空闲时,最小的毫秒数由操作系统和硬件的时间片分辨率确定。通常最小的“可休眠”时间是进程被系统的调度算法分配另一个时间片所需的时间。
例如,在 Windows(XP之后),Node 可能正在使用Windows 的 sleep
系统调用,而 Chrome 的结果似乎表明它使用比这更高分辨率的定时器。
sleep
吗? - Davidesleep
|Sleep
系统调用是否与此有关。我想JavaScript有自己的调度机制,粒度最终取决于语言特定浏览器实现。但是JavaScript是基于事件的,我认为它会在循环中检查事件,如果有任何计划和“过期”执行它们。这就是为什么它不准确(毫秒在这种情况下很大,因此应该期望准确性),也是为什么setTimeout()
的时间参数应该有限制的原因。 - Iharob Al Asimi对于旧版浏览器,您可以像文章中那样进行测试。我刚刚进行了一项测试,使用IE6中的10毫秒间隔的Firefox 2、Opera和Safari的延迟时间最低为10ms
setInterval
,平均值为55毫秒。setTimeout
的结果似乎较低,约为35毫秒。<script>
// number of times to call setTimeout before calculating average
var ITERATIONS = 200;
window.onload = function()
{
testTimeout(10, +new Date, 0, 0);
}
// calls setTimeout repeatedly at a specified interval, tracking the amount
// of time that passes between successive calls
function testTimeout(interval, last, sum, ii)
{
var time = +new Date;
var difference = time - last;
sum += difference;
if (ii % ITERATIONS == 1)
{
document.body.innerHTML = sum / ITERATIONS;
sum = 0;
}
window.setTimeout(
function() {
testTimeout(interval, time, sum, ii + 1)
}, interval);
}
</script>