当组件状态变化,Vue 会生成一棵全新的虚拟 DOM 树。如果每次都推倒重建,页面必然卡顿。Diff 算法就是「找出最小差异」的那把手术刀。Vue 2 的双端 Diff 已经很快,Vue 3 却用「快速 Diff」让它更快。
一、为什么需要 Diff?
响应式系统只能告诉你「某个组件脏了」,却不知道「脏在哪一行节点」。Diff 负责在同层级内精确定位「新增、删除、移动、更新」,避免整棵树的重绘。
二、Vue 2 的双端 Diff

想象新旧两条虚拟节点队列,各有一头一尾两个指针:
-
头头比对
新旧头节点相同 → 复用节点,两指针右移。
-
尾尾比对
新旧尾节点相同 → 复用节点,两指针左移。
-
旧头新尾比对
相同 → 把旧头节点移动到尾部,旧头右移、新尾左移。
-
新头旧尾比对
相同 → 把旧尾节点移动到头部,新头右移、旧尾左移。
如果四步都失败,就进入「暴力查找」:在旧队列里线性搜索与新头相同的节点。找到则移动,未找到则新增。
指针相遇即结束,剩余旧节点批量删除,剩余新节点批量新增。
双端 Diff 用 O(n) 时间完成「头尾夹击」,极大减少移动次数。
三、Vue 3 快速 Diff
双端 Diff 在「乱序列表」场景仍需多次线性搜索。Vue 3 把思路翻转:
- 先建立 key → index 的 Map,一次遍历即可知道是否存在可复用节点;
- 再求「最长递增子序列」(LIS),把「需要移动的节点」降到最少;
- 最后只做必要的 DOM 移动,其余节点原地复用。
结果:
- 纯新增或纯删除场景 → O(1) 完赛;
- 乱序场景 → O(n log n) 优于双端 Diff 的 O(n²)。
快速 Diff 把「比较」提前到内存,把「移动」推迟到最小集合,浏览器只需执行真正的 DOM 操作。
总结
Vue 2 用双端指针夹击「头尾」,Vue 3 用预序列化 + LIS 直击「最小移动」。理解指针走向,你就握住了性能优化的方向盘。