React 核心原理与虚拟 DOM:Diff 算法、Fiber 架构、渲染流程

本章是面试高频区,考察你从“会用”到“懂原理”的深度。你需要先理解虚拟 DOM 的设计动机,再掌握 Diff 算法三大策略、Fiber 架构的调度机制,最后串联出完整渲染流程。下面先用一张图建立回答框架,再通过三个问答卡片逐点击破。

虚拟 DOM 原理 Diff 算法三大策略 1. 同层比较(类型不同直接替换) 2. 列表 diff(key 复用 + 移动) 3. 组件级 shouldComponentUpdate Fiber 架构调度 1. 可中断渲染(时间切片) 2. 优先级调度(lane 模型) 3. 双缓冲 Fiber 树 渲染流程 1. Render 阶段(构建 Fiber 树) 2. Commit 阶段(DOM 操作 + 生命周期) 3. 批量更新 / 异步 setState

🟢 面试问题 1:请解释 React 的虚拟 DOM 是什么?Diff 算法是如何工作的?如何优化 Diff 性能?

面试官考察点1. 是否真正理解虚拟 DOM 的本质(JS 对象树 vs 真实 DOM)
2. Diff 算法三大策略的细节(同层、key、类型比较)
3. 优化手段(shouldComponentUpdate、PureComponent、React.memo)
回答框架① 定义虚拟 DOM:轻量 JS 对象描述 UI,核心价值是跨平台和批量更新。
② Diff 算法三个规则:
  • 同层节点只比较同一层,不跨层
  • 不同类型元素直接替换整棵子树
  • 列表 diff 通过 key 判断复用 / 移动 / 删除
③ 优化:使用 key 保持稳定;利用 PureComponent 或 memo 避免不必要的渲染。
简短示例回答“虚拟 DOM 是真实 DOM 的内存映射,通过 Diff 算法比较新旧虚拟树。Diff 只做同层比较,类型不同直接销毁重建;列表比较依赖稳定的 key 来最小化移动。我常在长列表使用唯一 id 作为 key,配合 React.memo 避免无关更新。”(约 90 字)
💡 可能追问• 为什么 Diff 算法不跨层?
• key 用 index 会有什么问题?举例说明。
• Fiber 架构下 Diff 算法有什么变化?
⚠️ 避坑提醒不要回答“Diff 算法是逐层递归比较”——实际是同层,且不同类型直接替换。也别忽略 key 对列表性能的影响,面试官会引导你举出“用 index 导致输入框错乱”的反例。
Fiber 架构面试追问路径 Fiber 架构本质 Q1: 时间切片如何实现? 利用 requestIdleCallback 或 可以中断的 work loop Q2: 优先级如何控制? lane 模型,高优先级打断 低优先级任务 Q3: 双缓冲树怎么切换? current 与 workInProgress 树 在 commit 阶段交换

🔵 面试问题 2:Fiber 架构相比之前 Stack Reconciler 有什么核心改进?它是如何做到可中断渲染的?

面试官考察点1. 对 Fiber 单元(节点)的理解(链表结构、任务分片)
2. 调度机制:requestIdleCallback / 可中断 workLoop
3. 优先级与双缓冲(current 树 / workInProgress 树)
回答框架① 旧架构递归不可中断 → Fiber 将递归转为链表遍历,配合时间切片。
② 每个 Fiber 节点代表组件 / 元素,包含 return、child、sibling 指针。
③ workLoop 通过剩余时间判断是否让出主线程,高优先级任务可打断低优先级。
④ 双缓冲:workInProgress 树构建完成后,在 commit 阶段替换 current 树。
简短示例回答“Fiber 把虚拟 DOM 拆成带链表指针的节点,每次处理一个单元并检查时间片剩余。如果不够,把控制权还给浏览器渲染。这种设计让长列表 diff 不再阻塞用户输入。双缓冲机制保证用户永远看到完整的树,不会被中间状态打断。”(约 95 字)
💡 可能追问• Fiber 的 effect list 在哪个阶段收集?
• 如何理解“调度”和“渲染”的分离?
• React 18 的并发模式与 Fiber 有什么关系?
⚠️ 避坑提醒不要只背概念,要说清楚“为什么需要可中断”——因为递归 diff 会占用大量帧时间导致掉帧。也别把 requestIdleCallback 当作唯一实现,React 自己实现了 scheduler 控制优先级。

🔵 面试问题 3:描述 React 从 setState 到界面更新的完整流程。render 阶段和 commit 阶段分别做什么?

面试官考察点1. 批量更新队列(batchUpdate)与优先级调度
2. Render 阶段:构建 Fiber 树、执行 diff、副作用收集
3. Commit 阶段:DOM 操作、生命周期调用、effect 清理
回答框架① setState 触发更新 → 进入调度(Scheduler)确定优先级。
② Render 阶段:从 root 开始深度优先遍历 Fiber 树,执行 Diff 生成 workInProgress 树,收集 side effect(插入、更新、删除)。
③ Commit 阶段:分 before mutation(getSnapshotBeforeUpdate)、mutation(DOM 操作)、layout(useLayoutEffect)三个子阶段,最后把 Fiber 树切换为 current。
简短示例回答“setState 后合并到更新队列,调度器根据优先级决定何时开始 render。Render 阶段递归遍历 Fiber 树,打上新增、更新、删除标记,生成 workInProgress 树。Commit 阶段按标记执行真实 DOM 操作,并依次触发 useEffect 清理和调用的回调。整个流程保证了 UI 的同步一致性。”(约 100 字)
💡 可能追问• useEffect 的回调在哪个阶段执行?为什么?
• 如果 render 阶段被高优先级打断,commit 阶段会怎样?
• 类组件中的 getDerivedStateFromProps 在哪个阶段被调用?
⚠️ 避坑提醒很多人误以为 useEffect 在 render 阶段执行——实际是 commit 阶段后异步执行。另外一定要分清“render 阶段可中断,commit 阶段不可中断”,这是面试核心区分点。
📌 章节小结: 三个问题层层递进:虚拟 DOM 是基础 → Diff 算法是核心 → Fiber 架构是性能保障 → 渲染流程是完整闭环。面试时先宏观描述再展开细节,用“可中断、优先级、双缓冲”这些关键词引导追问。多准备一个“列表 key 优化”的真实案例,能让面试官印象深刻。