引言:为什么需要 Fiber

React 16 引入的 Fiber 架构是 React 核心算法的一次彻底重写。在传统的 Stack Reconciler 中,组件树的递归遍历和中断不可控导致了长任务阻塞主线程的问题。Fiber 架构通过将渲染工作拆分为可中断的单元,配合优先级调度机制,实现了 Concurrent Mode 下流畅的用户体验。

1. Fiber 节点数据结构

Fiber 节点的核心字段定义如下:

function FiberNode(tag, pendingProps, key, mode) {
  this.tag = tag;                    // 组件类型标识
  this.key = key;                    // 协调 key
  this.type = null;                  // 关联的函数/类/原生标签
  this.stateNode = null;            // 真实 DOM 或组件实例
  this.return = null;                // 父 Fiber
  this.child = null;                 // 子 Fiber
  this.sibling = null;               // 兄弟 Fiber
  this.index = 0;                    // 同级位置
  this.pendingProps = pendingProps;  // 待处理 props
  this.memoizedProps = null;         // 已提交 props
  this.memoizedState = null;         // Hook 队列/State
  this.updateQueue = null;          // 更新队列
  this.alternate = null;            // 双缓冲树指针
  this.flags = NoFlags;             // 副作用标记
  this.lanes = NoLanes;             // 优先级车道
}

关键设计:双向链表(return/child/sibling)替代递归调用栈,使得中断与恢复成为可能;alternate 双缓冲实现 current 与 workInProgress 两棵树的无缝切换。

2. 工作循环(Work Loop)

Fiber 的工作循环分为两个阶段:

  • Begin 阶段:从根 Fiber 向下遍历,执行 render 函数,构建 Fiber 树,标记副作用(Placement/Update/Delete)
  • Commit 阶段:将 begin 阶段收集的副作用一次性应用到真实 DOM,执行生命周期和 useEffect
function workLoopConcurrent() {
  // shouldYield 在时间片用尽时返回 true
  while (workInProgress !== null && !shouldYield()) {
    performUnitOfWork(workInProgress);
  }
}

function performUnitOfWork(unitOfWork) {
  const current = unitOfWork.alternate;
  let next = beginWork(current, unitOfWork, renderLanes);
  unitOfWork.memoizedProps = unitOfWork.pendingProps;
  if (next === null) {
    completeUnitOfWork(unitOfWork);  // 上溯回退
  } else {
    workInProgress = next;           // 下探子节点
  }
}

3. 优先级调度与 Lane 模型

React 18 引入了基于 Lane 的优先级系统,将优先级编码为 31 位二进制数:

  • SyncLane (0b0000000000000000000000000000001) — 同步更新,如 flushSync
  • InputContinuousLane — 用户输入(滚动、拖拽)
  • DefaultLane — 普通更新(setState)、Promise 回调
  • TransitionLane — startTransition 包裹的低优先级更新
  • IdleLane — 空闲时才执行的更新

调度器(Scheduler 包)维护一个最小堆任务队列,按过期时间排序。高优先级任务可以打断低优先级任务的执行——被打断的低优先级工作会从上次中断的 Fiber 节点重新开始。

4. 时间切片(Time Slicing)

Scheduler 每 5ms 检查一次 shouldYield()(通过 MessageChannel 宏任务),如果当前帧的剩余时间不够,就让出主线程给浏览器。这意味着:

  • 最长连续阻塞时间被限制在 5ms
  • 浏览器有机会处理用户输入、执行动画、重排重绘
  • 多个低优先级更新可以被分散到多个帧中完成

5. 双缓冲机制详解

React 同时维护两棵 Fiber 树:

  • current tree:当前屏幕上显示的内容对应的 Fiber 树
  • workInProgress tree:正在构建的新 Fiber 树

commit 阶段完成后,root.current = workInProgress 切换指针。如果 commit 被打断或失败,current 树仍然保持一致的用户界面。

6. 工程实践中的关键注意点

自动批处理(Automatic Batching):React 18 将任意上下文中的多次 setState 合并(包括 Promise、setTimeout、原生事件)。

useTransition:包裹非紧急状态更新,保持 UI 响应性:

const [isPending, startTransition] = useTransition();
startTransition(() => {
  setHeavyList(filteredData);  // 低优先级,不阻塞输入
});

useDeferredValue:对计算昂贵的值进行"延期",返回旧值直到新值在空闲时准备好。

总结

Fiber 架构将 React 从"同步递归渲染器"重塑为"异步可中断调度器"。理解 Fiber 节点结构、双缓冲、Lane 调度模型和时间切片机制,是高效使用 Concurrent 特性、定位渲染性能瓶颈的基础。随着 React Server Components 和 Suspense 的普及,Fiber 也在持续演进——selective hydration 和 Offscreen API 进一步扩展了 React 的能力边界。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部