前言
- 运行机制
- 实际探究
步骤
简要回答
首先,我们要知道 setInterval 的运行机制,setInterval 属于宏任务,要等到一轮同步代码以及微任务执行完后才会走到宏任务队列,但是前面的任务到底需要多长时间,这个我们是不确定的
等到宏任务执行,代码会检查 setInterval 是否到了指定时间,如果到了,就会执行 setInterval,如果不到,那就要等到下次 EventLoop 重新判断
当然,还有一部分不确定的因素,比如 setInterval 的时间戳小于 10ms,那么会被调整至 10ms 执行,因为这是 setInterval 设计及规定,当然,由于其他任务的影响,这个 10ms 也会不精确
还有一些物理原因,如果用户使用的设备处于供电状态等,为了节电,浏览器会使用系统定时器,时间间隔将会被调整至 16.6ms
深入探究版
1.超时限制为>=4ms
在现代浏览器中,由于回调嵌套(嵌套级别至少为特定深度)或者经过一定数量的连续间隔而触发连续调用时,setTimeout
/setInterval
调用至少每4ms被限制一次
function f(){}
function cb(){
f()
setTimeout(cb,0)
}
setTimeout(cb,0)
- 在Chrome和Firefox 第五次连续的调用就会被限制
- Safari锁定了第六次通话
- Edge在第三次
- Gecko在
version56
已经这样开始尝试setInterval
(对setTimeout也一样) 。In Chrome and Firefox, the 5th successive callback call is clamped; Safari clamps on the 6th call; in Edge its the 3rd one. Gecko started to treat setInterval() like this in version 56 (it already did this with setTimeout(); see below).
从历史上来看,某些浏览器在执行此节流方式有所不同了,在setInterval
从任何地方的调用上,或者在setTimeout
嵌套级别至少达到一定深度的情况下调用嵌套时,要想在现代浏览器实现0毫秒延迟可以使用postMessage
注意:最小延迟
DOM_MIN_TIMEOUT_VALUE
为4ms,同时DOM_CLAMP_TIMEOUT_NESTING_LEVEL
是5(dom固定超时嵌套级别)
2.在非活动tab卡,超时限制为>=1000ms
为了减少背景选项卡的负载(和相关的资源使用),在不活动的资源卡将超时限制为1000ms以下
firefox从版本5开始实施该行为(可通过dom.min_background_timeout_value
首选项调整1000ms常量)。Chrome从版本11开始实现该行为,自Firefox 14中出现错误736602以来,Android版Firefox的背景标签使用的超时值为15分钟,并且背景标签也可以完全卸载
3.限制跟踪超时脚本
自Firefox 55起,跟踪脚本(例如Google Analytics(分析),Firefox通过其TP列表将其识别为跟踪脚本的任何脚本URL )都受到了进一步的限制。在前台运行时,节流最小延迟仍为4ms。但是,在后台选项卡中,限制最小延迟为10,000毫秒(即10秒),该延迟在首次加载文档后30秒生效。
控制此行为的首选项是:
- dom.min_tracking_timeout_value:4
- dom.min_tracking_background_timeout_value:10000
- dom.timeout.tracking_throttling_delay:30000
4.逾期超时
除了固定值意外,当页面(或OS /浏览器本身)忙于其他任务时,超时还会在以后触发。要注意的一个重要情况是,直到调用的线程setTimeout()终止,函数或代码段才能执行。例如:
代码语言:javascript复制function foo() {
console.log('foo has been called');
}
setTimeout(foo, 0);
console.log('After setTimeout');
// After setTimeout foo has been called
这是因为即使setTimeout以零的延迟被调用,它也被放置在队列中并计划在下一个机会运行。不是立即。当前执行的代码必须在执行队列中的功能之前完成,因此生成的执行顺序可能与预期的不同