html 本身不实现 diff 算法,diff 是 vue、react 等虚拟 dom 框架在 js 层实现的优化逻辑,用于对比新旧虚拟节点树、计算最小更新补丁并作用于真实 dom;它依赖可序列化、可预测的虚拟节点结构,而真实 dom 不可稳定快照、无法直接 diff。

直接说结论:HTML 本身不实现 diff 算法,diff 是虚拟 DOM 框架(如 Vue、React)在 JS 层做的逻辑,目的是避免直接操作真实 DOM 带来的高开销。你无法在纯 HTML 中“写一个 diff 算法”,但可以理解它怎么介入 HTML 更新流程、为什么必须有 key、以及没 key 时 DOM 怎么被误删重建。
为什么不能对真实 HTML 直接做 diff
真实 DOM 是浏览器内部结构,不可序列化为稳定树形对象;每次读取 document.body.innerHTML 都可能因浏览器自动修正(如补全 <tbody>、标准化属性顺序)而失真。diff 算法依赖可比、可预测的节点结构——这只能靠 JS 构造的虚拟 DOM 节点对象(如 <code>{ tag: 'div', props: { id: 'app' }, children: [...] })来承载。
常见错误现象:
- 用
innerHTML对比两次 HTML 字符串,发现空格、换行、属性顺序不同就判定“有差异” - 试图用
JSON.stringify(document.body)生成快照——结果是空对象或报错,因为 DOM 节点含循环引用和不可枚举属性
Vue 的 updateChildren 怎么对比两个 ul 的 li 列表
这是最常被问到的实际场景。Vue 不会把新旧列表全部打散重排,而是用双端指针 + key 匹配做 O(n) 级别比对。
使用前提:
- 新旧 vnode 列表都存在
key,且值唯一、稳定(比如后端返回的id,不是index) - 节点类型一致(都是
li,不是一会儿li一会儿div)
关键行为:
- 头头比、尾尾比、新头旧尾比、新尾旧头比 —— 四种情况快速复用已有节点
- 如果某旧
li的key在新列表里找不到,就直接removeChild - 如果某新
li的key在旧列表里找不到,就createElement并插入
没 key 时:Vue 退化为“按索引硬对”,['a','b','c'] → ['b','c','d'] 会把 'a' 当成要删的,'d' 当成要新增的,中间 'b','c' 虽然内容没变,但位置偏移了,也无法复用——DOM 节点被强制重新 create 和 insertBefore。
key 写成 index 为什么危险
这不是“不推荐”,而是会在列表增删时引发真实 DOM 错乱,且极难排查。
典型翻车场景:
- 列表初始为
[{id:1,name:'A'},{id:2,name:'B'}],渲染出<li key="0">A</li> <li key="1">B</li> - 在开头插入一条新数据:
[{id:3,name:'C'},{id:1,name:'A'},{id:2,name:'B'}] - 新 vnode 列表 key 变成
["0","1","2"],Vue 把旧key="0"(即 A)当成新key="0"(即 C)来 patch,结果 A 的 DOM 节点被复用去显示 C 的内容,但 A 的事件监听器、内部状态(如 input 的 value)全还在——用户看到的是 C 的文本,却操作着 A 的 input。
性能影响:看似只是 key 值变了,实际触发了整个子树的 patchVnode 递归,包括 props 更新、事件重绑、子组件 shouldComponentUpdate 判断等,远比用真实 id 多一次哈希查找代价高。
React 的 reconcileChildren 和 Vue 的区别在哪
核心目标一致:最小化 DOM 操作。但策略细节不同,直接影响你写 JSX 或模板时的行为。
关键差异点:
- React 默认要求列表项必须带
key,没写会警告;Vue 不强制,但没key就降级为索引比对 - React 的
reconcileChildren更激进复用:只要type(如div)相同,即使key不同也尝试clone节点并更新 props;Vue 更保守,key不匹配直接丢弃旧节点 - React 允许跨层级移动(如把子组件从
A移到B下),但需手动key保持一致;Vue 严格只比对同层,跨层移动会被识别为“删+增”
容易踩的坑:
- 在 React 中给动态组件写
key={Math.random()}—— 每次都新建实例,state 全丢 - 在 Vue 中用
v-for="item in list" :key="item.id",但后端返回的id是字符串,前端误当成数字比较导致 key 匹配失败
真正难的从来不是算法本身,而是你传给它的输入是否可靠:key 是否稳定、节点结构是否可预测、props 是否可序列化。这些地方一松动,O(n) 的 diff 就会退化成 O(n²) 的瞎猜。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











