React学习: requestIdleCallback
这个是 fiber 架构中的一个核心用到的 api
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 方法的缺陷
这个方法理论上可行,但为什么 React 团队又 polyfill 这个方法呢?
- 浏览器兼容不好的问题,requestIdleCallback 的 FPS 只有 20,也就是 50ms 刷新一次,远远低于页面流畅度的要求,所以 React 团队需要自己实现。
- 注意:timeRemaining 最大为 50ms,是有根据研究得出的,即是说人对用户输入的 100 毫秒以内的响应通常被认为是瞬时的,不会被人察觉到。
- 将空闲时间限制在 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