一、先给面试官的"王炸开场白"
你可以先来这一句 👇
React Fiber 是为了解决旧 Diff 递归不可中断的问题,引入的可中断、可优先级调度的架构;Diff 算法本身没变,但执行方式变了。
⚠️ 这一句,直接把你和"只背概念的人"区分开。
二、为什么 React 要引入 Fiber?
1️⃣ 旧架构的问题(Stack Reconciler)
React 16 之前:
sql
更新 → 递归 diff → 一口气算完 → commit
致命问题
- ❌ 不可中断
- ❌ 大组件树会卡主线程
- ❌ 无法区分优先级(动画、输入)
👉 用户体验:掉帧、卡顿
2️⃣ Fiber 解决了什么?
一句话总结 👇
把"递归不可中断" → 拆成"可中断的任务单元"
三、Fiber 是什么?(一定要讲清楚)
1️⃣ Fiber 本质不是算法,是数据结构
kotlin
interface Fiber {
type
key
stateNode
child
sibling
return
pendingProps
memoizedProps
memoizedState
flags
}
核心点
- 每一个组件 = 一个 Fiber 节点
- Fiber 是 链表结构,不是树递归
2️⃣ Fiber 结构长什么样?
yaml
parent
|
child ------ sibling ------ sibling
👉 用 child / sibling / return 模拟树
为什么不用数组?
- 链表更容易拆分、暂停、恢复
四、Fiber 架构是怎么"跑"起来的?
React 更新分两大阶段(必考)
sql
Render 阶段(可中断)
Commit 阶段(不可中断)
1️⃣ Render 阶段(核心)
做什么?
- Diff
- 生成 Fiber 树
- 标记副作用(flags)
特点:
- ✅ 可中断
- ✅ 可恢复
- ❌ 不操作 DOM
lua
workLoop
↓
performUnitOfWork
↓
next Fiber
2️⃣ Commit 阶段
做什么?
- 操作 DOM
- 执行 useEffect
特点:
- ❌ 不可中断
- ✅ 很快
3️⃣ 面试话术
Fiber 通过把 Render 阶段拆成小任务,配合浏览器空闲时间执行,实现了时间分片。
五、什么是时间分片(Time Slicing)?
核心 API
requestIdleCallback
React 内部思想:
php
while (有任务 && 有空闲时间) {
执行一个 Fiber
}
👉 不卡 UI 的关键
六、Diff 算法到底是怎么做的?
⚠️ 重点来了:
Diff 算法思想没变,执行模型变了
React Diff 的三大假设(必背)
1️⃣ 不同类型节点,直接删
css
<div /> → <span />
👉 不复用,整棵子树重建
2️⃣ 同一层级比较(O(n))
React 不会跨层 diff
只比较兄弟节点
3️⃣ key 决定节点复用
ini
{list.map(item => (
<Item key={item.id} />
))}
Diff 的真实过程(列表为例)
无 key(危险)
css
A B C
↓
B C D
👉 全部错位复用,性能差
有 key(正确)
scss
A(key1) B(key2) C(key3)
↓
B(key2) C(key3) D(key4)
👉 复用 B、C,只增删 A / D
面试话术
React Diff 是基于同层比较和 key 的启发式算法,把复杂度从 O(n³) 降到 O(n)。
七、Fiber 和 Diff 的关系(面试官最爱问)
错误理解 ❌
Fiber = 新 Diff
正确理解 ✅
Diff 算法没变,Fiber 改变的是 Diff 的执行方式和调度模型。
八、为什么 Fiber 能"中断",递归不行?
递归的问题
scss
diff(node) {
diff(node.child)
}
- 调用栈一旦开始,停不了
Fiber 的优势
ini
一个 Fiber = 一个工作单元
- 执行完一个就可以停
- 下次从 nextFiber 继续
九、面试官常见追问 & 满分回答
Q1:Fiber 是不是双缓存?
✅ 是
php
current Fiber Tree
workInProgress Fiber Tree
提交后互换引用。
Q2:useEffect 在哪执行?
👉 Commit 阶段之后
Q3:为什么 Render 阶段不能操作 DOM?
👉 因为可能被中断,多次执行会出问题。