【问题标题】:Why are setInterval calls not throttled for the first 4 executions?为什么前 4 次执行没有限制 setInterval 调用?
【发布时间】:2019-08-01 16:46:23
【问题描述】:

众所周知,JavaScript 中的超时会受到限制every 4ms on an active tab and every 1000ms on an inactive one。根据浏览器和配置的不同,此行为可能会略有变化,但通常是相同的。

为了完整起见,我将在此处引用相关部分:

超时限制为 >=4ms

在现代浏览器中,setTimeout()/setInterval() 调用在由于回调嵌套(嵌套级别至少为一定深度)或在特定数量之后触发连续调用时至少每 4 毫秒一次连续的间隔。

我想通过在默认 Chrome 实例上使用这个 sn-p 来向某人证明这一点:

let beforeStartingTheInterval = Date.now();
let intervalId = setInterval(()=>{ 
  let msPassed = Date.now()-beforeStartingTheInterval;
  if (msPassed > 20) clearInterval(intervalId); // stop after 20 ms
  console.log( msPassed + "ms have passed after starting the interval")
  }
,0);

几乎每次我运行该代码时,我都会得到以下输出:

1ms have passed after starting the interval
2ms have passed after starting the interval
3ms have passed after starting the interval
4ms have passed after starting the interval
8ms have passed after starting the interval
12ms have passed after starting the interval
16ms have passed after starting the interval
20ms have passed after starting the interval

可以看出,间隔是(通常)前四次每毫秒运行一次,之后每 >=4ms 运行一次。

为什么对于前 4 次执行,调用没有受到限制?我期望这个输出:

4ms have passed after starting the interval
8ms have passed after starting the interval
12ms have passed after starting the interval
16ms have passed after starting the interval
20ms have passed after starting the interval

或者至少一个在任意两次执行之间至少有 4 毫秒(甚至是第一次执行)

【问题讨论】:

    标签: javascript browser setinterval throttling


    【解决方案1】:

    答案在documentation that you linked to(重点是我的)

    在 Chrome 和 Firefox 中,第 5 次连续回调调用被钳制; Safari 夹在第 6 次调用;在 Edge 中,它是第三个。 Gecko 在 56 版中开始像这样对待 setInterval()(它已经使用 setTimeout() 做到了这一点;见下文)。

    【讨论】:

    • 我不认为这是我要问的“为什么”
    • @Adelin 为什么?因为这就是浏览器制造商指定的方式。还有什么好说的?
    【解决方案2】:

    又在网上搜索了一下,发现这是HTML5 standard:

    注意:定时器可以嵌套;然而,在 5 个这样的嵌套计时器之后,间隔被强制为至少 4 毫秒。

    【讨论】:

      【解决方案3】:

      为什么对于前 4 次执行,调用没有受到限制?

      我想第一个应该问的问题是为什么计时器会被限制?

      好吧,有些时候可能是这样的短运行计时器

      1) 难以实现,因为您必须使用硬件计时器或检查循环内的时间,才能准确地安排时间,循环必须运行得非常快。

      2) 消耗大量电池/计算时间

      3) 可能根本不需要,因为显示器大约每 60 fps 更新一次,即每 16 毫秒,所以如果您使用运行速度如此之快的计时器,您实际上不会以该速度看到输出。

      接下来的问题可能是那么为什么要使用这么短的计时器呢?

      其实有几个很好的理由:

      1) 推迟一个动作 a) 当前代码块,以 React 的 setState 为例 b) DOM 重新渲染

      2) 在主线程上“异步”执行长时间运行的任务而不阻塞 UI,通过释放它一毫秒时间。

      因此浏览器在调整定时器时间时出现问题:

      如果它限制了例如setState 延迟 4 毫秒,页面整体加载速度可能会变慢。但是,如果它不限制运行速度过快的 setInterval,则会浪费用户电池(如今大多数用户都在使用移动设备)。

      因此,浏览器非常快地执行几个计时器是有道理的,这样setTimeout(deferred, 0) 会立即执行,但在几次之后就会受到限制,以减少错误制作的渲染计时器/长时间运行算法的负面影响。

      “5 次”之后的“4ms”可能是这种考虑的平衡结果。

      【讨论】:

        【解决方案4】:

        https://humanwhocodes.com/blog/2011/12/14/timer-resolution-in-browsers/

        大多数浏览器还会根据不同的条件进行某种计时器限制。目的是在适当的时候节省电池 - 从理论上讲,您要么不会注意到差异,要么会很乐意在笔记本电脑或移动设备上换取更长的电池寿命。以下是计时器分辨率发生变化的一些情况:

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-04-12
          • 1970-01-01
          • 2020-08-31
          • 1970-01-01
          • 2018-02-17
          • 2014-08-29
          • 2020-02-25
          相关资源
          最近更新 更多