🎯 React Fiber 的出现
React16 之前的渲染模式是不可中断的,如果目前执行的任务过长,就会出现以下问题:
- 用户点按钮半天没反应
- 动画卡得像 PPT
- 页面像被人按下了暂停键
为了解决 React 渲染不友好的问题,让 React 变得更灵活(被打断也可以继续),所以需要一个全新的运行时架构
- 可切片
- 可暂停
- 可恢复
- 可优先级调度
🧠 React Fiber 的定义
Fiber 是可中断的渲染引擎,是把组件更新变成“可暂停的工作单元”的调度系统。
更具体的理解就是:
- Fiber 是一种链表结构的 vnode
- 它把每一个组件渲染拆成任务单元(unit of work)
- 所有任务都会被调度器按照优先级先后处理
🧩 React Fiber 的关键能力
💪 1. 可中断渲染(Time Slicing)
| 之前 | 现在 |
|---|---|
| 渲染不可中断,会阻塞其他事件,如用户点击等 | 渲染可中断,在任务执行过程中随时会给浏览器让步,等高优任务结束后再恢复执行 |
🎚️ 2. 优先级调度(Scheduler)
React Fiber 会给每个更新都贴上“优先级标签”,像这样:
| 更新类型 | 优先级(lane) |
|---|---|
| 用户点击 | 🟥 超高优先级 |
| 输入框输入 | 🟧 很高 |
| 普通渲染 | 🟩 中等 |
| transition | 🟦 低一点 |
| 日志、统计 | 🟪 淡淡的随缘优先级 |
用户点击了按钮 => 触发最高lane 任务 异步数据回来 => 触发中等lane任务 transition动效更新 => 触发更低lane任务
React 会根据这些任务的 lane 来决定当前应该执行哪个任务,以及后续任务的执行顺序。
🐱 3. 可恢复渲染(Pause & Resume)
React Fiber 中的每个节点都是一个 Fiber 对象,每次渲染一个 Fiber,都会在调度器中记录一个TODO List
Fiber A:处理中...
Fiber B:处理中...
Fiber C:处理中...
--给浏览器让步--
Fiber D:继续处理...
🔁 4. 双缓冲结构(alternate)
每个 Fiber 对象都有一个 alternate指针,分别指向两棵树:
current:现在正在屏幕上的版本workInProgress:正在构建的新版本
渲染期间 React 在 workInProgress 上完成所有的 diff 对比及更新操作,等渲染完毕后再将所有更改全部更新到current上面。
🧱 React Fiber 的执行流程
整个更新流程参考图如下所示:
🐱 1. 触发更新(setState / dispatch)
↓
🐱 2. 调度(分配 lane优先级)
↓
🐱 3. render 阶段(可中断)
- beginWork(创建新 fiber)
- completeWork(收集副作用 flags)
↓
🐱 4. commit 阶段(不可中断)
- mutation:动 DOM
- layout:执行 layout effect
- passive:执行普通 effect
render 可以被打断,commit 绝对不会被打断
因为 commit 阶段动 DOM 和副作用,不能搞一半停一半,不然页面要变成“半成品料理”。
🎚️ 调度系统(Scheduler)
React 其内部会周期性调用 shouldYield() 询问浏览器是否需要让步,如果浏览器需要渲染动画、响应用户操作,React 会暂停自己的渲染工作。
如果让步:
pause → 等下再继续 → resume
🏎 lane 模型
在 Fiber 内部,每个更新会被标记成 lane:
00001 → 高优先级更新
00010 → 普通更新
00100 → transition
01000 → 空闲任务
…
比如来了一个点击事件(超高优先级):
pendingLanes = 00001
React 检查当前渲染是否比它慢:
- 若慢,立即 中断当前渲染
- 处理高优先级任务
- 再回来继续做之前没做完的
🎤 总结
- “Fiber 就是一个可以被切片、暂停、恢复的渲染引擎,它把每个组件拆成可调度的工作单元,并用 lane 模型管理优先级,让 React 能在高负载下保持流畅的用户交互。”
- “render 阶段可中断,commit 阶段不可中断,这是保证用户看到 UI 一致性的关键。”
- “双缓冲结构让 React 可以在后台构建新的 UI,再一次性替换出来。”
“时间切片让渲染不再阻塞用户输入。”