React 核心原理与虚拟 DOM:Diff 算法、Fiber 架构、渲染流程
本章是面试高频区,考察你从“会用”到“懂原理”的深度。你需要先理解虚拟 DOM 的设计动机,再掌握 Diff 算法三大策略、Fiber 架构的调度机制,最后串联出完整渲染流程。下面先用一张图建立回答框架,再通过三个问答卡片逐点击破。
🟢 面试问题 1:请解释 React 的虚拟 DOM 是什么?Diff 算法是如何工作的?如何优化 Diff 性能?
| 面试官考察点 | 1. 是否真正理解虚拟 DOM 的本质(JS 对象树 vs 真实 DOM) 2. Diff 算法三大策略的细节(同层、key、类型比较) 3. 优化手段(shouldComponentUpdate、PureComponent、React.memo) |
| 回答框架 | ① 定义虚拟 DOM:轻量 JS 对象描述 UI,核心价值是跨平台和批量更新。 ② Diff 算法三个规则:
|
| 简短示例回答 | “虚拟 DOM 是真实 DOM 的内存映射,通过 Diff 算法比较新旧虚拟树。Diff 只做同层比较,类型不同直接销毁重建;列表比较依赖稳定的 key 来最小化移动。我常在长列表使用唯一 id 作为 key,配合 React.memo 避免无关更新。”(约 90 字) |
| 💡 可能追问 | • 为什么 Diff 算法不跨层? • key 用 index 会有什么问题?举例说明。 • Fiber 架构下 Diff 算法有什么变化? |
| ⚠️ 避坑提醒 | 不要回答“Diff 算法是逐层递归比较”——实际是同层,且不同类型直接替换。也别忽略 key 对列表性能的影响,面试官会引导你举出“用 index 导致输入框错乱”的反例。 |
🔵 面试问题 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 优化”的真实案例,能让面试官印象深刻。