🧩 一、为什么要有 Fiber?
在老版本 React(16 之前)中,更新机制采用递归调用栈(Stack Reconciler) 。其问题是显而易见的:
- 当组件树很大时,递归更新会长时间占用主线程。
- 会导致掉帧、交互卡顿。
- 浏览器没法在渲染中途"打断"它。
可以这么形容旧架构:
"React 是个话唠,一旦开始讲 JSX,就不肯停下来------即使浏览器喊它喘口气,它也要先把这棵树讲完。" 😩
于是,React 团队决定造一个新的"中断友好型"调度机制:Fiber架构。
🧠 二、核心思想:把调用栈拆成链表
从计算机底层角度上看,原先 React 的递归模式其实类似于:
scss
function renderComponent(node) {
node.render();
node.children.forEach(renderComponent);
}
------一次深度调用,没法暂停、中断或回溯。
Fiber 的革命性改造在于:
把函数调用栈从"隐式栈"变成可控制的数据结构。
也就是说:
- React 不再依赖 JS 引擎的调用栈;
- 而是用它自己的**链表结构(Fiber tree)**来表示组件更新进度;
- 每个 Fiber 就像一个"任务单元",可被挂起、恢复、或丢弃。
🧬 Fiber 节点结构的本质
以极简化形式看,每个 Fiber 节点大致类似:
go
const fiber = {
tag: "ClassComponent",
type: MyComponent,
pendingProps: {},
memoizedState: {},
return: parentFiber, // 父节点
child: childFiber, // 第一个子节点
sibling: nextFiber, // 下一个兄弟节点
alternate: oldFiber, // 上次渲染的旧节点
};
这是一棵单向链表表示的树 ,也是 React 能实现时间切片调度的基础。
🌳 Fiber 树让渲染可以"分段执行":
React 不再是一口气渲染整个虚拟DOM,而是可以:
- 渲染一部分;
- 暂停;
- 把控制权交还给浏览器;
- 再接着从上次中断处继续。
这就是 Fiber 的调度魔法 ✨。
⚙️ 三、React Fiber 的三大核心阶段
Fiber 的运行大致分成三个阶段,每一环都对应底层的架构思想。
1️⃣ Reconciliation 阶段(协调阶段)
目标:找出哪些组件需要更新,生成对应的工作单元(Fiber树)。
这一阶段是可中断的 。
在源码中被称为 beginWork() 与 completeWork()。
React 会在这阶段:
- 根据
props、state判断变化; - 比对新旧 Fiber 树(即 "Diff" 操作);
- 创建新的 Fiber 链表节点。
🎯 当浏览器需要渲染、滚动、或用户输入时,
React 可以暂停当前 Diff 工作,让浏览器优先刷新帧率。
2️⃣ Commit 阶段(提交阶段)
目标:把协调结果真正挂到 DOM 上。
这阶段是同步的、不可中断的(就像肾上腺素爆发的那一瞬间💥)。
包含:
- Mutation(操作真实 DOM)
- Layout(执行生命周期钩子)
代码层面就是执行一系列 commit hooks(例如 useLayoutEffect、componentDidMount)。
3️⃣ Scheduler 调度机制(任务计划者)
这是 React Fiber 背后最"计算机科学"的部分。
React 通过 优先级队列 + 消息循环时间片 模拟"协作式多任务":
- 每个 Fiber Task 都有一个优先级(Normal、High、Idle...);
- React 会检查任务是否超出帧预算(约 16ms);
- 若超时就交还主线程;
- 然后在下一帧继续被打回调度队列。
我们可以用 JS 模拟下时间切片思路👇
scss
const tasks = [...Array(1000).keys()].map(i => () => console.log("任务", i));
function scheduler() {
const start = performance.now();
while (tasks.length && performance.now() - start < 5) {
const task = tasks.shift();
task();
}
if (tasks.length) requestIdleCallback(scheduler);
}
scheduler();
🧠 这段代码的精神,就是 React Fiber 的心脏。
🔩 四、Fiber 的性能底层逻辑:从浏览器主线程说起
从浏览器渲染机制讲:
- 主线程要负责 布局、绘制、事件处理、JS执行;
- 如果 React 的 render 占用过久,就会阻塞用户交互;
- Fiber 通过"切片"策略,让 JS 与渲染交替进行。
React 内部每隔几十毫秒会询问:
"浏览器,你现在忙吗?如果你有空,我继续Diff。"
这背后用到的关键浏览器API是:
requestIdleCallback()(早期实验)- 后来使用
MessageChannel + Scheduler自定义时间片
这保证了 React 在高负载场景下依然流畅不卡顿。
🧭 五、学习 Fiber 架构的建议路线
想真正理解 Fiber,不是看"代码跑什么",而是明白"为什么要这么跑 "。
推荐一个递进式学习路线 💡:
🧱 第一步:理解浏览器渲染管线
- 了解事件循环 (Event Loop)
- 理解
requestAnimationFrame与requestIdleCallback - 掌握 JS 的"不可中断"本质(单线程)
🧪 第二步:阅读简化版 Fiber 实现
例如,我们可以模拟一个最小版本的 "Fiber 调度器":
ini
function performUnitOfWork(fiber) {
console.log("渲染组件:", fiber.name);
if (fiber.child) return fiber.child;
let nextFiber = fiber;
while (nextFiber && !nextFiber.sibling) nextFiber = nextFiber.return;
return nextFiber ? nextFiber.sibling : null;
}
// 手动构造 fiber 树
const fiberTree = {
name: "App",
child: { name: "Header", sibling: { name: "Footer" } }
};
// Scheduler 循环
let next = fiberTree;
while (next) {
next = performUnitOfWork(next);
}
如果你能理解上面代码为何能替代递归,就能真正踏入 Fiber 的世界。
⚛️ 第三步:研读 React 源码(从 ReactFiberWorkLoop.js 入手)
核心文件不在多,而在精:
ReactFiber.js:定义 Fiber 数据结构;ReactFiberWorkLoop.js:协同逻辑;Scheduler.js:调度模块;ReactFiberReconciler.js:组件状态驱动。
🧩 六、React Fiber 的未来方向
目前(截至 React 19+),Fiber 架构已进入可并发渲染 (Concurrent Rendering) 阶段。
这意味着 React 可以:
- 同时启动多个渲染任务;
- 自动决定哪一个任务先完成;
- 动态中止低优先级任务。
未来的方向包括:
- 🔄 Offscreen Rendering:提前渲染但暂不展示;
- 💡 Selective Hydration:在SSR中按需恢复交互;
- 🧠 AI assisted rendering pipeline:结合 AIGC 自动生成组件级优化策略。
🧠 七、总结:Fiber是"会喘气的调用栈"
一句话总结:
"Fiber 就是一个能暂停、恢复、优先级调度的虚拟调用栈。"
它让 React 从"纯函数式UI库"升华成一个运行时系统 ,
可以对计算时间进行操作,而不仅是 DOM。
🚀 Fiber 让 React 拥有了操作时间的能力。
也正如操作系统管理进程那样,React 开始管理渲染任务。
💬 最后的小彩蛋
如果要打个比喻:
- 🌳 React 组件树:森林
- 🧩 Fiber:一株能暂停生长的树苗
- ⏱️ Scheduler:园丁,决定哪个先开花
- 🧠 你:老天爷,制定天气和季节的规律
所以,学习 Fiber 的关键,不在于"啃源码",
而在于理解