Skip to main content

React Fiber 树遍历机制

React Fiber 树的遍历是一个基于深度优先循环遍历过程。它与 React 15 及之前版本依赖递归调用栈不同,Fiber 架构的核心改进是将遍历过程拆解为可中断的工作单元

整个遍历过程主要发生在render 阶段。下面我们来拆解这个过程。

1. Fiber 数据结构:遍历的基础

Fiber 树之所以能被循环遍历,关键在于其独特的链表式数据结构。每个 Fiber 节点通过三个核心指针来连接:

  • child: 指向第一个子节点。
  • sibling: 指向下一个兄弟节点。
  • return: 指向节点,用于工作完成后的回溯。

这种结构将一棵树转换为了一个可通过指针遍历的链表。

2. 遍历执行流程:workLoopperformUnitOfWork

整个遍历过程由一个名为 workLoop 的循环驱动。

// 同步模式下的工作循环
function workLoopSync() {
while (workInProgress !== null) {
performUnitOfWork(workInProgress);
}
}

workInProgress 是一个全局指针,指向下一个需要被处理的 Fiber 节点performUnitOfWork 函数是遍历的核心,它处理当前节点,并返回下一个要处理的节点。

遍历的两大阶段:beginWorkcompleteWork

performUnitOfWork 对每个节点的处理分为“递”和“归”两个阶段。

  • 递(beginWork):当“进入”一个节点时,会执行 beginWork。它的主要任务是创建或复用子 Fiber 节点,并建立起父子间的 childreturn 连接。
  • 归(completeWork):当“离开”一个节点时,会执行 completeWork。它主要处理节点自身的副作用(如 DOM 更新)并收集有副作用的节点,形成副作用链表(effectList)

遍历的顺序逻辑

performUnitOfWork 函数决定了遍历的具体顺序。

  1. 优先处理子节点:对当前节点执行 beginWork 后,如果它有 child,则下一个工作单元就是该 child 节点。这保证了深度优先的遍历顺序。
  2. 处理兄弟或回溯:如果当前节点没有 child (即叶子节点),则执行 completeWork。之后:
    • 若它有 sibling (兄弟节点),则下一个工作单元是sibling 节点
    • 若没有 sibling,则通过 return 指针回溯到父节点,并执行父节点的 completeWork
  3. 循环直至根节点:这个过程不断重复,直到完成根节点 rootFibercompleteWork,此时 workInProgress 变为 null,遍历结束。

3. 可中断与恢复:链表遍历的核心优势

链式遍历让“可中断”成为可能。

在并发模式下,workLoop 会在执行每个工作单元后检查是否还有剩余时间。

// 并发模式下的工作循环
function workLoopConcurrent() {
while (workInProgress !== null && !shouldYield()) {
performUnitOfWork(workInProgress);
}
}
  • 中断:如果 shouldYield() 返回 true (表示时间用尽或有更高优先级任务),循环会暂停。因为 workInProgress 指针保存了当前处理到的节点,所以可以随时停止。
  • 恢复:当下次浏览器有空闲时间时,workLoop 会从上次保存的 workInProgress 节点继续执行,实现无缝恢复。

总结

React Fiber 树的遍历可以总结为以下几点:

  • 数据结构:使用 childsiblingreturn 指针构建的链表树
  • 遍历方式深度优先遍历
  • 执行方式:通过 workLoop 循环和 performUnitOfWork 函数驱动,替代了传统的递归
  • 核心流程:每个节点经历 beginWork (递)completeWork (归) 两个阶段。
  • 关键特性:基于链表的遍历是可中断、可恢复的,这是实现时间切片和并发更新的基础。