同级比较是Diff算法仅在同一深度层级比对新旧节点的设计,因跨层移动发生率低于0.1%且会使复杂度升至O(n³),故放弃跨层复用以保障日常更新效率。

“同级比较”是指 Diff 算法只在虚拟 DOM 树的**同一深度层级**上,对新旧节点逐个比对,而完全不追踪或尝试匹配跨层级移动的节点。它不是“懒得跨层”,而是基于真实 UI 行为规律做出的主动设计取舍。
为什么只做同级比较?
核心原因在于:Web 应用中,DOM 节点跨层级移动(比如把一个 li 从列表内部直接提到父容器外、或嵌入到另一个组件深层)属于极少数异常操作,日常开发几乎不会发生。React 和 Vue 的团队通过大量真实项目数据验证了这一点——跨层移动的频率远低于 0.1%,却会让算法复杂度从 O(n) 暴涨到 O(n³)。
不跨层级,具体怎么体现?
-
层级一旦断开,就放弃复用:比如旧树中
<div><p>A</p></div>,新树变成<p>A</p>(p被提到根层),React 不会尝试把原p“提上来”,而是直接销毁整个div子树,再新建独立的p节点。 -
子节点只和同辈比,不和祖先/后代比:旧节点
[A, B, C]变成新节点[C, D, A],算法只在当前数组层面对齐 —— 找到C和A的位置变化,移动它们;但绝不会去检查C是否曾是某个深层嵌套节点的子元素。 -
组件层级也遵循该规则:若旧组件
<List>渲染出<Item>,新结构里<Item>被直接写在模板顶层,Diff 不会关联这两个Item,哪怕它们 props 完全一致 —— 因为它们已不在同一组件调用层级。
那跨层级改动就一定慢吗?
不一定,但需要开发者配合:
- 用 CSS 显示隐藏 替代 DOM 移除/插入(例如
display: none或visibility: hidden),保持节点仍在原层级; - 在列表等动态结构中,始终为子项提供稳定、唯一的
key,让同级复用更精准; - 避免手动操作真实 DOM 来改变节点层级关系,否则会破坏虚拟 DOM 的层级假设。
本质上,“同级比较”不是能力缺陷,而是用确定性换性能:放弃对小概率事件的兜底,换来日常更新的极致效率。框架相信——你写的 UI 结构,本就不该频繁“上下乱跳”。

















