Skip to content

一、为什么 React 一定要有 Fiber?(动机)

1️⃣ 老 React(Stack Reconciler)的问题

在 React 16 之前,React 的更新流程是:

txt
setState
 → 同步递归 diff
 → 一口气算完整棵树
 → 更新 DOM

❌ 问题本质

  • 不可中断
  • 不可暂停
  • 不可恢复

如果组件树很大:

  • diff 占用 JS 主线程
  • 用户滚动 / 输入会卡顿
  • 浏览器无法插手

👉 这和 Vue effect 模型完全不同 Vue 是“点更新”,React 是“树更新”,React 必须解决这个问题。

2️⃣ React 的选择

React 没走 Vue 的「更细粒度响应式」,而是选择:

  • 让“render 本身”可被中断、拆分、重试

👉 Fiber 就是为这个目标设计的。

二、Fiber 是什么(一句话版)

  • Fiber 是一种“可中断的虚拟调用栈 + 数据结构”

更直白一点:

  • Fiber = 把递归 diff,改写成「可暂停的循环任务」

三、Fiber 的本质:把“树”变成“链表 + 栈”

1️⃣ 一个 Fiber 节点是什么?

每个 Fiber 节点 = 一个组件 / DOM 节点

ts
interface Fiber {
  type           // 组件类型
  key
  stateNode      // DOM 或 class 实例
  return         // 父 fiber
  child          // 第一个子 fiber
  sibling        // 下一个兄弟 fiber

  pendingProps
  memoizedProps
  memoizedState  // hooks 就在这

  flags          // 副作用标记
}

⚠️ 注意: Fiber 不是 Virtual DOM Virtual DOM 是 描述 UI Fiber 是 调度 + 执行单元

2️⃣ 为什么是 child / sibling / return?

因为这样可以:

  • 不用递归
  • 用 while 循环
  • 每一步都可以暂停
txt
App
 └─ A
    ├─ B
    └─ C

变成:

txt
App.child → A
A.child → B
B.sibling → C

四、Fiber 的核心能力:可中断 render

1️⃣ render 阶段(可中断)

React 把更新分成两步:

txt
Render 阶段(可中断)
Commit 阶段(不可中断)

Render 阶段做什么?

  • 执行组件函数
  • 调用 Hooks
  • diff Fiber
  • 标记 flags(增 / 删 / 改)

👉 不操作 DOM

2️⃣ Commit 阶段(必须一次完成)

  • 操作 DOM
  • 执行 useEffect cleanup / create
  • ref 赋值

👉 一旦进入,绝不中断

3️⃣ 中断是怎么实现的?

ts
while (nextUnitOfWork && !shouldYield()) {
  nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
}
  • shouldYield():浏览器要控制权
  • 保存当前 Fiber
  • 下次从这里继续

👉 Fiber = 可恢复的执行上下文

五、Fiber 和 Scheduler 的关系(并发来源)

1️⃣ Scheduler 决定“什么时候跑”

  • requestIdleCallback(早期)
  • MessageChannel
  • 优先级(lane)
txt
高优先级(点击)
低优先级(列表)

2️⃣ Fiber 决定“跑到哪里停”

  • 每个 Fiber = 一个 work unit
  • 可暂停
  • 可丢弃
  • 可重做

👉 并发 = Scheduler + Fiber

六、为什么 Fiber 能“重跑 render”而不怕?

这是 React 的核心设计前提:

  • render 必须是纯函数
txt
同样的 props + state
 → 同样的 UI

所以:

  • render 跑一半被丢弃 ❌ 没关系
  • 再跑一遍 ✅ 一样的结果

👉 这点 Vue effect 很难做到

七、Fiber vs Vue effect(你最关心的对比)

维度Vue3 effectReact Fiber
粒度属性级组件级
更新方式精确触发render 重跑
中断能力
调度友好一般极强
并发基础scheduler + jobscheduler + fiber

一句话总结:

  • Vue 用「更细的依赖」避免算
  • React 用「可中断计算」硬算

八、Hooks 为什么必须依赖 Fiber?

因为:

  • Hooks 状态存在 fiber.memoizedState
  • render 重跑时按顺序取
  • Fiber 保证 同一组件的 Hook 链稳定
txt
Fiber
 └─ memoizedState
     ├─ hook1
     ├─ hook2
     └─ hook3

👉 没有 Fiber,就没有 Hooks

九、常见误解澄清(面试高频)

❌ Fiber = 并发

  • Fiber 是基础设施,不等于并发

❌ Fiber = 更快

  • Fiber 有时更慢,但更“可控”

✅ Fiber = 可调度、可中断、可恢复

十、终极一句话总结

  • Fiber 不是为了性能,而是为了“让 React 能被操作系统一样调度”