React Fiber 是如何实现更新过程可控?
参考答案:
更新过程的可控主要体现在下面几个方面:
- 任务拆分
- 任务挂起、恢复、终止
- 任务具备优先级
任务拆分
在 React Fiber 机制中,它采用"化整为零"的思想,将调和阶段(Reconciler)递归遍历 VDOM 这个大任务分成若干小任务,每个任务只负责一个节点的处理。
任务挂起、恢复、终止
- workInProgress tree
workInProgress 代表当前正在执行更新的 Fiber 树。在 render 或者 setState 后,会构建一颗 Fiber 树,也就是 workInProgress tree,这棵树在构建每一个节点的时候会收集当前节点的副作用,整棵树构建完成后,会形成一条完整的副作用链。
- currentFiber tree
currentFiber 表示上次渲染构建的 Filber 树。在每一次更新完成后 workInProgress 会赋值给 currentFiber。在新一轮更新时 workInProgress tree 再重新构建,新 workInProgress 的节点通过 alternate 属性和 currentFiber 的节点建立联系。
在新 workInProgress tree 的创建过程中,会同 currentFiber 的对应节点进行 Diff 比较,收集副作用。同时也会复用和 currentFiber 对应的节点对象,减少新创建对象带来的开销。也就是说无论是创建还是更新、挂起、恢复以及终止操作都是发生在 workInProgress tree 创建过程中的。workInProgress tree 构建过程其实就是循环的执行任务和创建下一个任务。
挂起
当第一个小任务完成后,先判断这一帧是否还有空闲时间,没有就挂起下一个任务的执行,记住当前挂起的节点,让出控制权给浏览器执行更高优先级的任务。
恢复
在浏览器渲染完一帧后,判断当前帧是否有剩余时间,如果有就恢复执行之前挂起的任务。如果没有任务需要处理,代表调和阶段完成,可以开始进入渲染阶段。
- 如何判断一帧是否有空闲时间的呢?
使用前面提到的 RIC (RequestIdleCallback) 浏览器原生 API,React 源码中为了兼容低版本的浏览器,对该方法进行了 Polyfill。
- 恢复执行的时候又是如何知道下一个任务是什么呢?
答案是在前面提到的链表。在 React Fiber 中每个任务其实就是在处理一个 FiberNode 对象,然后又生成下一个任务需要处理的 FiberNode。
终止
其实并不是每次更新都会走到提交阶段。当在调和过程中触发了新的更新,在执行下一个任务的时候,判断是否有优先级更高的执行任务,如果有就终止原来将要执行的任务,开始新的 workInProgressFiber 树构建过程,开始新的更新流程。这样可以避免重复更新操作。这也是在 React 16 以后生命周期函数 componentWillMount 有可能会执行多次的原因。

任务具备优先级
React Fiber 除了通过挂起,恢复和终止来控制更新外,还给每个任务分配了优先级。具体点就是在创建或者更新 FiberNode 的时候,通过算法给每个任务分配一个到期时间(expirationTime)。在每个任务执行的时候除了判断剩余时间,如果当前处理节点已经过期,那么无论现在是否有空闲时间都必须执行该任务。过期时间的大小还代表着任务的优先级。
任务在执行过程中顺便收集了每个 FiberNode 的副作用,将有副作用的节点通过 firstEffect、lastEffect、nextEffect 形成一条副作用单链表 A1(TEXT)-B1(TEXT)-C1(TEXT)-C1-C2(TEXT)-C2-B1-B2(TEXT)-B2-A。
其实最终都是为了收集到这条副作用链表,有了它,在接下来的渲染阶段就通过遍历副作用链完成 DOM 更新。这里需要注意,更新真实 DOM 的这个动作是一气呵成的,不能中断,不然会造成视觉上的不连贯(commit)。
题目要点:
React Fiber 是 React 的一个核心更新算法,旨在提高更新过程的灵活性和性能。
1. 引入 Fiber 架构
- 什么是 Fiber?
- Fiber 是 React 的一种新的协调算法,用于管理和调度更新。它允许 React 在多个帧中分片地完成任务,使更新过程更具响应性和可控性。
2. 优先级调度
- 任务优先级:
- Fiber 架构引入了优先级调度机制,将更新任务分为不同的优先级。例如,用户交互事件(如点击)通常具有更高的优先级,而数据获取等低优先级任务则可能被推迟处理。
- 实现方式:使用优先级队列,确保高优先级的任务可以在较低优先级的任务之前完成。
3. 分片更新
- 更新分片:
- Fiber 允许将更新任务分片成较小的单元(Fiber 节点),使得每次更新只处理一个 Fiber 节点的更新,从而避免长时间阻塞主线程。
- 实现方式:在每一帧中,React 处理一个小的 Fiber 节点,允许 UI 在每帧之间保持响应。
4. 可中断的任务
- 任务可中断性:
- Fiber 使得任务在执行过程中可以被中断和恢复。长时间运行的任务可以被分割成较小的部分,React 可以在空闲时间恢复任务,确保页面保持响应。
- 实现方式:通过 Fiber 的调度器,任务在需要时可以被挂起,并在之后的空闲时间继续执行。
5. 增量渲染
- 增量渲染:
- Fiber 支持增量渲染,即在一次更新中只渲染部分组件。这样可以减少每次渲染的工作量,并提升性能。
- 实现方式:通过 Fiber 节点的链表结构,逐步应用更新,避免全量渲染。
6. 恢复和回溯
- 恢复和回溯:
- Fiber 支持恢复和回溯机制。在更新过程中,如果发现错误或需要中断,Fiber 可以回退到安全的状态,保证应用的一致性和稳定性。
- 实现方式:使用 Fiber 树的结构来保存中间状态和更新历史,必要时可以回到之前的状态。
总结
- 优先级调度:引入优先级机制,确保高优先级任务优先处理。
- 分片更新:将更新分片为较小单元,减少长时间阻塞。
- 可中断的任务:支持任务的中断和恢复,提升响应性。
- 增量渲染:支持逐步渲染,减少每次渲染的工作量。
- 恢复和回溯:支持回退机制,保证应用一致性。
React Fiber 的这些特性使得 React 的更新过程更加灵活、可控,提升了应用的性能和用户体验。