React学习: requestIdleCallback

这个是 fiber 架构中的一个核心用到的 api
更新于: 2022-05-15 00:45:58

requestIdleCallback

  • 利用浏览器的空余时间执行任务,如果有较高优先级的任务要执行的时候,当前执行可以被终止,优先执行更高级别的任务

屏幕刷新率和 FPS 的关系

当前大多数的屏幕刷新率都是 60HZ,一秒 60 帧(FPS 为 60),也就是每秒屏幕刷新 60 次,此时一帧的时间为 16.7ms(1000ms/60)低于 60HZ 人眼就会感知卡顿掉帧等情况。

浏览器的一帧说的就是一次完整的重绘。

前端浏览器所说的渲染频率 FPS(Frames Per Second)是每秒传输帧数,即是每秒刷新的次数,理论上 FPS 越高人眼觉得界面越流畅。

requestIdleCallback 和 requestAnimationFrame 区别

  • requestAnimationFrame 的回调会在每一帧确定执行,属于高优先级任务
  • requestIdleCallback 的回调则不一定,有空闲时间才执行,属于低优先级任务

requestAnimationFrame 比起 setTimeout、setInterval 的优势主要有两点:

  • requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒 60 帧。
  • 在隐藏或不可见的元素中,requestAnimationFrame 将不会进行重绘或回流,这当然就意味着更少的的 cpu,gpu 和内存使用量。
  • aric: 当浏览器切换tab时,不会执行任务

requestIdleCallback 方法的缺陷

requestIdleCallbck执行

这个方法理论上可行,但为什么 React 团队又 polyfill 这个方法呢?

  1. 浏览器兼容不好的问题,requestIdleCallback 的 FPS 只有 20,也就是 50ms 刷新一次,远远低于页面流畅度的要求,所以 React 团队需要自己实现。
  2. 注意:timeRemaining 最大为 50ms,是有根据研究得出的,即是说人对用户输入的 100 毫秒以内的响应通常被认为是瞬时的,不会被人察觉到。
  3. 将空闲时间限制在 50ms 内意味着即使在闲置任务开始后立即发生用户操作,用户代理仍然有剩余的 50ms 可以在其中响应用户输入而不会产生用户可察觉的滞后。

polyfill

React 团队则是用 requestAnimationFrame 和 postMessage 模拟实现的,本篇就不讲了,有兴趣的可以去了解看看。

使用

    

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>requestIdleCallback</title>
</head>
<body>
<style>
  #box {
    height: 100px;
    padding: 10px;
    border: 1px solid #ccc;
    background: #eee;
    margin: 10px;
  }
</style>
<div id="box"></div>
<button id="action-calc">step1: Calc</button>
<button id="action-change-color">step2: ChangeColor</button>
<script>
  var maxNum = 90000;
  var box = document.getElementById('box');
  var actionCalc = document.getElementById('action-calc');
  var actionChangeColor = document.getElementById('action-change-color');

  function largeCalcTask(deadline) {
    // console.log('timeRemaining: ',deadline.timeRemaining());
    var num = 0;
    for (var i = 0; i < maxNum; i++) {
      var value = 'text: ' + Math.random();
      box.innerText = value;
      // console.log('value1: ' + value);
      num += i;
    }

    requestIdleCallback(largeCalcTask);
    console.log('latest num: ' + num);
  }

  actionCalc.addEventListener('click', function () {
    console.log('start calc');
    requestIdleCallback(largeCalcTask)
  });

  actionChangeColor.addEventListener('click', function () {
    console.log('start change color');
    box.style.backgroundColor = 'green';
  });

</script>
</body>
</html>

 

参考

https://www.bilibili.com/video/BV11A4y1S7KN?p=37

https://www.bilibili.com/video/BV11A4y1S7KN?p=38

https://segmentfault.com/a/1190000039287134