前言
React 是一个用于构建用户界面的声明式库,但你可能不知道,它内部为了解决“更新性能”和“响应性”的矛盾,引入了一套完整的调度系统:Fiber 架构。
Fiber 并不是 React 的一个 API,而是其底层的“重新实现”。它是 React 16 引入的一项重大重构,旨在让 React 具备“增量渲染”、“任务中断与恢复”、“可控优先级更新”等能力。
这篇文章将尝试从 设计动因 → 数据结构 → 渲染流程 → 调度机制 → 并发特性 全面讲清楚 Fiber 的本质。
一、为什么要有 Fiber?
1. 经典 Stack Reconciler 的局限
在 Fiber 之前,React 使用的是递归调用的方式来构建和比较组件树(stack reconciler)。它的问题是:
- 无法中断:整个更新过程一旦开始,无法暂停。
- 更新耗时长时会卡顿:例如深层组件树更新,全部计算完才能交给浏览器渲染。
- 缺乏优先级:高优更新(如输入响应)无法“插队”。
2. Fiber 的出现
Fiber 架构重新实现了 React 内部的更新流程:
- 更新过程可中断:基于协程思想,每次处理一点任务,然后“让出”主线程。
- 支持任务重用和回溯:Fiber 本质上是一个可变链表,而不是纯递归。
- 引入优先级调度模型:不同更新任务可以设置不同的优先级,避免“无脑全量更新”。
二、什么是 Fiber?它是一种什么结构?
Fiber 是 React 内部用来表示组件的最小单元。每一个组件(函数组件、类组件、原生标签)在 React 内部都会对应一个 Fiber 节点。
可以把 Fiber 想象成“可中断的工作单元”。
一个 Fiber 节点包含的信息:
interface Fiber {
tag: WorkTag; // 类型,如 FunctionComponent、HostComponent 等
key: null | string;
elementType: any;
type: any;
return: Fiber | null; // 父节点
child: Fiber | null; // 第一个子节点
sibling: Fiber | null; // 下一个兄弟节点
stateNode: any; // DOM 节点或组件实例
pendingProps: any; // 新的 props
memoizedProps: any; // 上次渲染的 props
memoizedState: any; // 上次渲染的 state
alternate: Fiber | null; // 当前 Fiber 与旧 Fiber 的双缓存
flags: Flags; // 标记该节点需要做哪些操作(插入、更新、删除)
}
注意:Fiber 节点之间形成的是一棵单向链表结构的树,而不是递归调用栈。
这使得 React 可以在构建组件树的过程中随时暂停、恢复甚至放弃某个分支的工作。
三、Fiber 的两个阶段:render 阶段 与 commit 阶段
React 的更新流程分为两个阶段:
1. render 阶段(也叫 reconciliation)
- 构建新的 Fiber 树
- 对比旧 Fiber 树,标记变化(diff)
- 这一步是纯计算,不会操作 DOM
- 可被中断
2. commit 阶段
- 根据 render 阶段打的标记(flags)来执行实际的 DOM 操作
- 包括插入、更新、卸载等
- 是不可中断的同步操作
React 的 Fiber 架构核心价值之一,就是把这两个阶段彻底分开,让 “render 可以异步、commit 仍同步”。
四、调度机制:如何做到可中断?
1. Scheduler 的职责
React 通过一个叫 scheduler 的模块来管理更新任务的调度过程:
- 每个更新任务被包装为一个 “Fiber Work”
- 每个任务有优先级(如同步、高、中、低)
- 浏览器空闲时由 scheduler 分片调度这些任务
这个机制很像「浏览器里的小型操作系统」。
2. requestIdleCallback 与时间切片
早期 React 使用 requestIdleCallback 来模拟时间切片:
function workLoop(deadline) {
while (deadline.timeRemaining() > 1 && nextUnitOfWork) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
}
后来 React 自己实现了一套跨平台调度器,不再依赖浏览器提供的 API,更加稳定可控。
五、优先级模型:Lanes 系统
React 18 引入了新的优先级模型 —— Lanes
你可以把 Lanes 理解为“跑道”,每个更新被分配一个优先级 lane,在调度阶段会根据 lane 的优先级决定先执行谁。
常见优先级包括:
- 同步更新(SyncLane)
- 用户交互(InputLane)
- 空闲时间更新(IdleLane)
- Transition(并发过渡)
这样,比如一个用户输入框的更新就能优先于动画、日志等不重要的任务,最大化交互流畅性。
六、并发特性(Concurrent Mode)带来的能力
得益于 Fiber 架构和调度器的配合,React 实现了一种“并发渲染”的能力(不是多线程,而是多段执行)。
这带来了很多新的能力:
- 自动批处理(automatic batching)
- useTransition/useDeferredValue 等延迟更新 hook
- 可中断、可恢复渲染流程
- Suspense 的流式渲染(server rendering)
Fiber 架构是 React 并发能力的基石,没有 Fiber,就没有所谓“并发 React”。
七、总结:Fiber 是 React 内核的重新定义
你可以不手动操作 Fiber,也不会直接感知它的存在,但你用的每一个 React 特性,都依赖它的支撑。
我们可以这样理解 Fiber 带来的改变:
| 能力 | Stack Reconciler(旧) | Fiber |
|---|---|---|
| 可中断更新 | ❌ | ✅ |
| 设置优先级 | ❌ | ✅ |
| 增量构建视图 | ❌ | ✅ |
| 更复杂的异步场景支持 | ❌ | ✅ |
| 并发渲染 | ❌ | ✅ |
Fiber 是 React 为了应对大型 UI 应用的复杂交互而量身定制的底层架构。它的设计不是为了“快”,而是为了让系统“可控”,从而变得可靠和用户友好。
最后
如果你是 React 的日常使用者,了解 Fiber 并不是为了操作它,而是为了更好地理解:
- 为什么组件会“闪一下”?
- 为什么
useTransition能让 UI 变丝滑? - 为什么更新被“打断”了?
- 为什么 Suspense 有的地方能用、有的地方不能用?
这些看似“高级”的特性,其实都和 Fiber 紧密相关。
Fiber 架构背后的思想是:响应式 UI 的本质是调度问题。React 做的,就是把调度从浏览器夺回来,交给自己掌控。