各浏览器的setInterval实现细节测试

如何以指定的帧速绘制动画?用setInterval来调度误差大吗?下面的测试会给出解答。

环境和设定

浏览器

  • Windows Chrome 108
  • Android Chrome 107
  • iOS Safari 16.0
  • Windows Firefox 107
  • Android Firefox 108 Beta

测试15fps的帧速(帧间隔毫秒为1000/15),测试持续60秒,期间页面一直保持显示状态(不切换到后台,不息屏)

测试代码

在线演示见CodePen setInterval actual interval test

Interval set: <span id="interval0">0span><br/>
Average interval <span id="interval1">0span><br/>
<script>
function main() {
  let interval = 1000 / 15;
  document.querySelector('#interval0').textContent = interval ;
  let span = document.querySelector('#interval1');
  let count = 0;
  let startTime = performance.now();
  let handle = setInterval(() => {
    let date = new Date();
    count++;
    let avgInterval = (performance.now() - startTime) / count;
    span.textContent = avgInterval.toFixed(2);
  }, interval);
}
document.addEventListener('DOMContentLoaded', main);
script>

测试结果

setInterval的实测平均间隔

occasion \ platform Windows Chrome Android Chrome macOS Safari iOS Safari Windows Firefox Android Firefox
page visible 66.01 66.01 66.69 78.45 66.67
page visible (battery power saving mode) 66.01 66.01 89.76 78.36 66.68
page hidden
page hidden (battery power saving mode)

解读

根据以上测试结果,我能得出的结论是:

Chrome的setInterval似乎对delay参数进行了floor()处理(不支持delay的小数部分),采取自校准策略使得调度较为准时(当参数delay为整数时调度不会顺延),似乎未针对省电模式切换策略。

Safari的setInterval分两种情况:非省电模式中支持delay参数的小数部分,采取自校准策略使得调度较为准时;省电模式中采取累积延迟策略(顺延)。

Windows Firefox的setInterval采取累积延迟策略,Android Firefox的setInterval采取自校准策略,两者似乎未针对省电模式切换策略。

这么乱,接下来怎么办

自校准策略和累积延迟策略的setInterval各有其适用场合,类似于对即时性要求高容许丢包的UDP协议和对准确要求高容许延迟的TCP协议适用与不同场景。

作者分别给出基于这两种策略的两套setInterval实现(见Gist setInterval implementations),使得前端开发者在不同的应用场景下选择不同策略的setInterval实现,当然开发者应优先检测浏览器的setInterval策略,如果合适则优先采用浏览器原生的setInterval。

你可能感兴趣的:(Front-end,javascript)