引言:为什么需要 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) — 同步更新,如 flushSyncInputContinuousLane— 用户输入(滚动、拖拽)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 的能力边界。

发表评论 取消回复