如果回调被阻止,setInterval 的不同行为

Different behaviour for setInterval if callback is blocked

我 运行 在 Firefox 58 和 Chrome 63 Linux

中的代码大致相同
count = 0
intv = 0
function f(){
    let a
    console.log('start', performance.now())
    for (let i=0;i<50000000;i++){
        a=i
    }
    if (count % 5 === 0){
        for (let i=0;i<100000000;i++){
            a=i
        }
    }
    console.log('end', performance.now())
    count++
}
function k(){
    intv=setInterval(f, 100)
}
function e(){
    clearInterval(intv)
}

k()

可能需要调整两个常量的确切值以确保阻止第 2 和第 3 次回调 在 Firefox 中我得到了

start 2657023.3000000003
end 2657123.92
start 2657124.2800000003
end 2657155.84
start 2657224.2
end 2657265.06
start 2657324.62
end 2657363.3000000003
start 2657424.72
end 2657461.6
start 2657524.94
end 2657624.7800000003

如你所见,从第 3 个回调开始的每个回调都是从执行第 2 个回调开始的 100ms * N

并在 Chrome

start 463571.0300000001
end 464149.28
start 464150.49500000005
end 464178.63000000006
start 464178.775
end 464204.61500000005
start 464270.91000000003
end 464308.09
start 464370.94
end 464415.37500000006
start 464470.93500000006
end 464511.48000000004

每个回调在 100ms * N 从第一次回调开始执行

那么这两个浏览器实现的 setInterval 之一是错误的还是 setInterval 的行为取决于实现?

setInterval/setTimeout 的确切行为取决于实现。除了 MDN ) and in this draft update of HTML5 中讨论的浏览器和上下文之间的差异(也在评论中引用)。

HTML 文档包含说明和步骤,这些说明和步骤表明在使用计时器时不应期望某些标准的准确性:

This API does not guarantee that timers will fire exactly on schedule. Delays due to CPU load, other tasks, etc, are to be expected.

  1. Optionally, wait a further user-agent defined length of time.

特定 JavaScript 引擎的行为也会影响计时:

  • 运行 代码的时间分析和优化可以随着时间的推移改变和提高特定代码部分的速度,
  • 间歇性垃圾收集有时会减慢代码速度,但有时不会,
  • 运行 时间环境可以动态改变引擎调用定时器回调的能力。打开 30 个选项卡的低速笔记本电脑的计时可能与使用打开单个选项卡的高速处理器完全不同,没有其他应用程序 运行ning 并且不需要 OS 页面内存。

我个人在 Firefox 中进行性能测试的经验是,它是高度不可预测的。如果测试顺序颠倒,则通过定时比较两种代码算法会产生不同的结果。例如第一个算法 运行 首先似乎更快,但是如果第二个算法是 运行 首先它似乎更快。或者 运行多次执行性能测试会产生完全不同的结果。

我对这些变幻莫测的反应是 运行 以不同顺序多次进行性能测试,并使用结果的统计度量作为 性能指南 。最快的时间可能表明代码 可以 运行 的速度有多快,平均值可能是更好的现实指南,而最慢的时间,特别是如果它是系列中的第一个,对于 运行 仅一次的代码可能是典型的。