React Fiber
详细介绍 React 中的 fiber 机制和原理
什么是 Fiber
Fiber 就是一个 js 对象, 用于描述一个 react 工作单元. 早期的 react 中是使用虚拟 DOM 来进行描述, 现在的 fiber 架构中则是用 fiber, fiber 可以理解为一个更强大的虚拟 DOM
一个简化的 fiber 对象如下:
1 | { |
React 工作时, 会沿着 fiber 树形结构进行, 对比每个 fiber 旧的 props 和新的 props 来确定是否需要更新组件, 如果主线程有更重要的工作, 如响应用户输入, 则可以中断当前工作并返回主线程上的任务
Fiber 结构
1 | function FiberNode( |
Fiber 工作原理
Fiber 工作原理最核心的点就是可以中断和恢复, 增强了 react 的并发性和响应性
工作原理中的几个关键点:
- 单元工作: 每个 fiber 节点代表一个单元, 所有 fiber 节点构成一个 fiber 链表树, 使 react 可以细粒度控制节点行为
- 链接属性: child, sibling, return 分别表示子节点, 兄弟节点和父节点, 构成了 fiber 之间的链接关系, 使 react 能够遍历 fiber 树来确定从哪里开始, 继续或停止工作
- 双缓冲技术: react 在更新时会根据现有的 fiber 树 (current tree) 创建一个新的临时树 (work in progress (WIP) tree), WIP tree 包含了当前更新受影响的最高节点和其下所有子孙节点, WIP tree 在后台更新, current tree 则是显示在界面上的视图. WIP tree 更新完成后会复制其他节点并最终替换掉 current tree. 因为同时维护两个 fiber tree, 所以 react 可以随时进行比较, 中断或恢复等操作, 这种机制同时保证了渲染性能和 UI 稳定
- State & props: memoizedProps, pendingProps, memoizedState 字段让 react 知道组件的上一个状态和即将应用的状态, 通过比较这些值, react 可以决定组件是否需要更新, 避免不必要的渲染
- 副作用追踪: flags 和 subtreeFlags 标识 fiber 及其子树中需要执行的副作用, 如 DOM 更新, 生命周期调用等, react 会收集这些副作用, 在 commit 阶段一次性执行
Fiber 工作流程
主要分为两个阶段:
Reconciliation 调和
调和阶段确定了哪些部分的 UI 需要更新, 通过比较新的 props 和旧的 fiber 树来确定, 调和阶段可中断和恢复
调和阶段分为两个小阶段:
- 创建与标记更新节点: beginWork, 这个阶段会进行判断 fiber 是否需要更新, 以及判断 fiber 子节点是更新还是复用, 随后执行执行 fiber 节点的调和(处理诸如新 fiber 的创建, 旧 fiber 的删除或现有 fiber 的更新). beginWork 完成后就会进入 completeWork 流程
- 收集副作用列表: completeUnitOfWork & completeWork: completeUnitOfWork 负责遍历 fiber 节点, 同时记录有副作用的节点的关系, completeWork 在 completeUnitOfWork 中被调用, 主要用于记录 fiber 的副作用标志, 为子 fiber 创建链表以及根据 fiber 的 tag 进行不同的处理
Commit 提交
提交阶段会通过遍历在 Reconciliation 阶段创建的副作用列表来更新 DOM 并执行收集到的副作用, 提交阶段不可中断
提交阶段分为三个小阶段:
- 遍历副作用列表: commitBeforeMutationEffects, 遍历 fiber, 处理节点删除和确认节点在 before mutation 阶段是否有要处理的副作用
- 正式提交: commitMutationEffects, 递归遍历 Fiber, 更新副作用节点
- 处理 layout effects: commitLayoutEffects, 处理那些由 useLayoutEffect 创建的 layout effects