Skip to content

Fiber 渲染过程分析

在 React 的 Fiber 架构中,渲染过程被分为两个阶段:

  1. 调和阶段(Reconciliation / Render Phase):这一阶段是可中断的,React 会根据新旧虚拟 DOM 树进行比较,生成 Fiber 树,找到需要更新的地方。这个阶段可以被暂停和恢复,用于优先处理更紧急的任务。
  2. 提交阶段(Commit Phase):这一阶段是不可中断的,React 会将调和阶段计算出的更新结果应用到实际的 DOM 中,并执行副作用(如 useEffectcomponentDidMount)。

那么,如何判断调和阶段的计算已经完成并可以进入提交阶段呢?

一、判断计算完成进入渲染的关键步骤

React 会在调和阶段完成后,执行以下步骤来判断何时可以进入提交阶段:

  1. Fiber 树遍历完成

    • 在调和阶段,React 会从根节点开始遍历整个 Fiber 树(组件树),对每个 Fiber 节点进行必要的计算(如 diff、状态更新、props 更新等)。
    • 每个节点都有可能发生变化(如 props 变更、state 变更、DOM 变化等),这些变化被标记在 Fiber 树中。
    • 当整个 Fiber 树遍历完,并且所有需要的变化都计算完毕时,React 会认为调和阶段的工作已经完成。
  2. 是否存在高优先级任务

    • Fiber 架构的一个特点是调和阶段是可中断的。React 在调和阶段会不断检查是否有更高优先级的任务(例如,用户输入、动画等)。
    • 如果有高优先级任务,它会暂停当前的渲染,优先处理这些任务,随后恢复之前的 Fiber 树遍历。
    • 只有当没有更高优先级的任务存在时,React 才会认为调和阶段可以继续,直至完成。
  3. 对比新旧虚拟 DOM

    • 在调和阶段,React Fiber 通过Diff 算法对比新旧虚拟 DOM 树,找到哪些节点需要更新。这些节点被打上不同的标记(flags),标记的节点表明这些节点在提交阶段需要更新。
    • 一旦 Diff 完成,React 便清楚哪些部分需要进行更新,这标志着调和阶段的工作已经完成。
  4. Fiber 树上的副作用链

    • 每个需要更新的节点都会被打上“副作用”标记(例如插入、更新、删除 DOM 节点等)。这些副作用会被添加到 Fiber 树的副作用链上。
    • 当所有的副作用都已经准备好时,React 就可以进入提交阶段,并将这些副作用应用到实际的 DOM 中。

二、判断可以进入提交阶段的信号

React 在调和阶段有一个状态叫 workInProgress,它指向当前正在处理的 Fiber 树。当 Fiber 树的所有节点都被遍历并处理完成后,React 会检测是否可以进入提交阶段。具体来说:

  1. workInProgressnull

    • 如果 workInProgress 为空,意味着当前的 Fiber 树遍历已经完成,React 可以进入提交阶段。
  2. 没有未完成的任务

    • React 的调度器会检查是否有未完成的工作单元(Work Unit)。如果没有未完成的任务,React 认为调和阶段已经结束,准备进入提交阶段。
  3. 低优先级任务被处理完毕

    • 如果当前存在低优先级的任务,React 可能会继续推迟提交阶段,并优先处理更紧急的任务。当低优先级任务被完成后,再进入提交阶段。

三、提交阶段的标志

一旦调和阶段完成,React 进入提交阶段,有以下几个关键标志:

  1. 生成了副作用列表

    • 调和阶段完成后,React 会生成一个需要提交的副作用列表。这些副作用包括 DOM 操作、生命周期方法调用(componentDidMountcomponentDidUpdate 等)以及 useEffect 中定义的副作用。
  2. 根 Fiber 节点的 EffectTag 标记

    • 当整个调和阶段完成时,根 Fiber 节点(Root Fiber)上会有一个特殊的 EffectTag,表示整个 Fiber 树的变化已经计算完毕,所有需要更新的节点都被打上了标记。
  3. 开始执行 DOM 更新

    • 当 Fiber 树生成的副作用链准备好之后,React 开始执行 DOM 更新。这个过程是同步的,且不可中断。React 会根据 Fiber 树上的标记,逐个执行 DOM 操作。
  4. 执行生命周期方法和副作用

    • 在提交阶段,React 会在 DOM 更新完成后,执行生命周期方法(如 componentDidMountcomponentDidUpdate)以及 useEffect 中的副作用函数。

四、总结

  1. 调和阶段的结束标志:React Fiber 树遍历完成,所有需要更新的节点都打上了副作用标记,并且没有高优先级的任务需要处理时,调和阶段结束。
  2. 判断可以进入提交阶段workInProgress 指向的 Fiber 树已经完成,且没有未完成的任务,React 就会开始进入提交阶段。
  3. 提交阶段的执行:提交阶段是同步的,不可中断,React 会将副作用列表中的操作应用到真实的 DOM 上,并执行必要的副作用函数。

通过这些机制,React 保证了在不阻塞主线程的情况下进行高效的渲染,并最大限度地提升用户的交互体验。