Fiber
requireIdleCallback
核心API功能介绍
利用浏览器的空余时间执行任务,如果有更高优先级的任务执行,当前任务可以被终止,执行优先级高级别的任务。
requestIdleCallback(function(deadline) {
// deadline.timeRemaining() // 获取浏览器的空余时间
})
浏览器空余时间
页面是一桢一桢绘制出来的,当每秒绘制数达到60时,页面是流畅的,小于这个值时,用户会感觉到卡顿。
1s 60桢,每一帧分到时间是 1000 / 60 ≈ 16 ms,如果每一帧执行的时间小于16ms,就说明浏览器有空余时间。
如果任务在剩余的时间内没有完成则会停止任务执行,继续优先执行主任务,也就是说 requestIdleCallback 总是利用浏览器的空余时间执行任务
Fiber
问题
React 16 之前的版本更新VirtualDOM的过程是采用递归实现的,这种比对方式有一个问题,就是任务一旦开始进行就无法中断,如果应用中组件数量庞大,主线程被长时间占用,直到整颗VirtualDOM树比对更新完成之后主线程才被释放,主线程才能执行其他任务。这就会导致一些用户交互,动画等任务无法立即得到执行,页面就会产生卡顿,影响用户体验。
核心问题:递归无法中断,执行重任务耗时长。JavaScript又是但页面线程,无法同时执行其他任务,导致任务延迟页面卡顿,用户体验差。
解决方案
- 利用浏览器空闲时间执行任务,拒绝长时间占用主线程。
- 放弃递归只采用循环,因为循环可以被中断
- 任务拆分,将任务拆分成一个个的小任务
实现思路
在Fiber方案中,为了实现任务的终止再继续,DOM比对算法被分成了两部分: 1. 构建 Fiber (可中断) 2. 提交 Commit (不可中断)
DOM 初始渲染:virtualDOM -> Fiber -> Fiber[] -> DOM
DOM 更新操作: newFiber vs oldFiber -> Fiber[] -> DOM
Fiber对象
{
type 节点类型(元素 | 文本 | 组件)
props 节点属性
stateNode 节点DOM对象 | 组件实例对象
tag 节点标记(hostRoot | hostComponent | classComponent | functionComponent)
effects 数组,存放需要更改的 fiber 对象
effectTag 当前 fiber 要被执行的操作(新增 | 删除 | 修改)
parent 当前 fiber 的父级 fiber
child 当前 fiber 的子级 fiber
sibling 当前 fiber 的下一个兄弟 fiber
alternate fiber 备份 fiber , 比对时使用
}