React Fiber
在 React 16 之前的版本对比更新 VirtualDOM 的过程是采用 Stack 架构实现的,也就是循环加递归,这种方式的问题是一旦任务开始进行就无法被中断。
如果应用中的组件数量庞大, Virtual DOM 的层级比较深,主线程被长期占用,知道整颗 Virtual DOM 树比对更新完成之后主线程才能被释放,主线程才能执行其他的任务,这会导致一些用户交互,动画等任务无法得到立即执行,页面会卡顿,非常影响用户体验。
核心问题是:递归无法被中断,执行任务耗时长,JavaScript 是单线程的,和 Native GUI 互斥,比较 VirtualDOM 的过程中无法执行其他任务,导致任务延迟页面卡顿,用户体验差。
Fiber 的思路
- 放弃递归调用,采用循环模拟递归,因为循环可以被随时中断
- Fiber 将大的渲染任务拆分成一个个小任务(Fiber节点的创建)
- React 使用
window.requestIdleCallback
去利用浏览器的空闲时间去执行小任务,React 在执行一个任务单元后,查看是否有其他高优先级的任务,如果有,放弃占用线程,先执行优先级高的任务
关于
window.requestIdleCallback
的作用,可以查看 https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback ,例子可以查看 https://github.com/zjy4fun/requestIdleCallback
Fiber 的结构
// 简易版 Fiber 对象
type Fiber = {// 组件类型 div、span、组件构造函数type: any,// DOM 对象stateNode: any, // 指向自己的父级 Fiber 对象return: Fiber | null,// 指向自己的第一个子级 Fiber 对象child: Fiber | null,// 指向自己的下一个兄弟 iber 对象sibling: Fiber | null,
}
Fiber 两阶段
Render
构建 Fiber 对象,构建链表,在链表中标记要执行的 DOM 操作 ,可中断。
Commit
根据构建好的链表进行 DOM 操作,不可中断。
参考
https://juejin.cn/post/6993973502852202503