JavaScript——定时器为什么是不精确的

简介: JavaScript——定时器为什么是不精确的

前言

  • 运行机制
  • 实际探究

步骤

简要回答

首先,我们要知道 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()终止,函数或代码段才能执行。例如:

function foo() {
  console.log('foo has been called');
}
setTimeout(foo, 0);
console.log('After setTimeout');
// After setTimeout    foo has been called

这是因为即使setTimeout以零的延迟被调用,它也被放置在队列中并计划在下一个机会运行。不是立即。当前执行的代码必须在执行队列中的功能之前完成,因此生成的执行顺序可能与预期的不同

学无止境,谦卑而行.

目录
相关文章
|
6月前
|
JavaScript
JS定时器
JS定时器
56 0
|
5月前
|
JavaScript 前端开发 安全
JavaScript基础-定时器:setTimeout, setInterval
【6月更文挑战第13天】JavaScript中的`setTimeout`和`setInterval`是异步编程的关键工具,用于按计划执行代码。`setTimeout`在延迟后执行一次,而`setInterval`则周期性执行。常见问题包括忘记清除定时器导致内存泄漏,递归使用`setTimeout`可能引发无限递归,以及字符串代码执行的安全隐患。解决方法包括使用`clearTimeout`和`clearInterval`,设置递归终止条件,以及优先使用函数表达式。理解定时器的非精确性并采用错误处理策略也是实践中的重要技巧。通过示例展示了如何延迟显示消息和周期性打印计数。
89 2
|
1月前
|
JavaScript 前端开发
js之一次性定时器
js之一次性定时器
11 1
|
1月前
|
JavaScript 前端开发
js之永久定时器
js之永久定时器
13 1
|
3月前
|
JavaScript 前端开发
解决在JS中阻止定时器“重复”开启问题、Vue中定时器的使用
这篇文章讨论了在JavaScript和Vue中如何避免定时器重复开启的问题,并提供了一个模拟场景和代码示例,演示了在开启新定时器前清除旧定时器的方法。
解决在JS中阻止定时器“重复”开启问题、Vue中定时器的使用
|
3月前
|
JavaScript 前端开发
js之永久定时器
js之永久定时器
|
3月前
|
JavaScript 前端开发
|
3月前
|
JavaScript 前端开发
js之永久定时器
js之永久定时器
32 0
|
3月前
|
JavaScript 前端开发
js之一次性定时器
js之一次性定时器
30 0
|
4月前
|
JavaScript 前端开发
vue 模拟随机变速的动态打字特效【支持多行文本】(含css实现闪烁光标,js动态改变setInterval定时器的时间间隔)
vue 模拟随机变速的动态打字特效【支持多行文本】(含css实现闪烁光标,js动态改变setInterval定时器的时间间隔)
91 1