zoukankan      html  css  js  c++  java
  • 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以零的延迟被调用,它也被放置在队列中并计划在下一个机会运行。不是立即。当前执行的代码必须在执行队列中的功能之前完成,因此生成的执行顺序可能与预期的不同

  • 相关阅读:
    P3619 魔法
    【HAOI2014】遥感监测
    cdcq的独立博客上线辣!-> http://cdcq.coding.me/blog/
    重复型图床
    【BZOJ1213】高精度开根
    前后端技术
    【HAOI2011】problem b
    【HAOI2011】problem a
    【BZOJ4553】【TJOI2016】【HEOI2016】序列
    【HAOI2015】 T1
  • 原文地址:https://www.cnblogs.com/wangyang0210/p/13807883.html
Copyright © 2011-2022 走看看