什么是 reconciliation
What is reconciliation
一句话:reconciliation(协调)是「比较新旧虚拟 DOM 树, 决定要对真实 DOM 做哪些操作」的整个过程。 diff 算法是它的一部分。
diff 和 reconciliation 什么关系?这是本题的考点:diff 是「怎么比」的算法, reconciliation 是「比 + 决定 + 提交」的完整流程。 说它们是一回事不算错,但分得清更好。
React 16 之后的 Fiber 架构把这个过程拆成两个阶段 —— 这是必答的:
- render 阶段(可中断)—— 构建 Fiber 树、做 diff、 标记要改什么。这个阶段可以被打断和恢复, 所以高优先级的更新(比如用户输入)能插队。
- commit 阶段(不可中断)—— 把标记好的改动一次性打到真实 DOM 上, 然后跑
useEffect。这一段必须同步完成, 否则用户会看到半渲染的界面。
为什么要能中断?因为老架构(Stack Reconciler)是递归的、一旦开始就停不下来, 大列表更新时会阻塞主线程十几毫秒以上, 输入卡顿。Fiber 用链表 + 循环替代递归, 每处理一小块就检查「有没有更急的事」。这就是「并发特性」的基础(见 #344)。
会追问:「StrictMode 为什么渲染两次?」—— 因为 render 阶段可能被中断和重跑, 所以渲染函数必须是纯的; 两次渲染就是帮你把不纯的地方暴露出来(见 #332)。
In one line: reconciliation is the whole process of comparing the new and old virtual DOM trees and deciding which operations to run on the real DOM. The diff algorithm is one part of it.
How do diff and reconciliation relate? That is the point of the question: diff is the algorithm for how to compare; reconciliation is the full compare, decide and commit flow. Calling them the same thing is not wrong, but telling them apart is better.
The Fiber architecture, from React 16 on, splits the process into two phases — answer this every time:
- Render phase (interruptible) — build the Fiber tree, diff, mark what has to change. This phase can be paused and resumed, which is how a high-priority update such as typing jumps the queue.
- Commit phase (not interruptible) — apply the marked changes to the real DOM in one pass, then run
useEffect. This part must finish synchronously, otherwise users would see a half-rendered screen.
Why does it need to be interruptible? Because the old Stack Reconciler was recursive and could not stop once it started, so a large list update blocked the main thread for tens of milliseconds and typing stuttered. Fiber replaces recursion with a linked list plus a loop, and after each small chunk it checks whether something more urgent came in. This is the foundation of the concurrent features (see #344).
Follow-up: “Why does StrictMode render twice?” — because the render phase can be interrupted and re-run, so the render function has to be pure; the double render is there to expose the impure parts (see #332).