diff算法是一种通过同层的树节点进行比较的高效算法其有两个特点:
- 比较只会在同层级进行, 不会跨层级比较
- 在diff比较的过程中,循环从两边向中间比较
diff算法的在很多场景下都有应用,在vue中,作用于虚拟dom渲染成真实dom的新旧VNode节点比较
diff整体策略为:深度优先,同层比较
vue通过diff更新的例子:
第一次循环后,发现旧节点D与新节点D相同,直接复用旧节点D作为diff后的第一个真实节点,同时旧节点endIndex移动到C,新节点的 startIndex 移动到了 C
第二次循环后,同样是旧节点的末尾和新节点的开头(都是 C)相同,同理,diff 后创建了 C 的真实节点插入到第一次创建的 B 节点后面。同时旧节点的 endIndex 移动到了 B,新节点的 startIndex 移动到了 E
第三次循环中,发现E没有找到,这时候只能直接创建新的真实节点 E,插入到第二次创建的 C 节点之后。同时新节点的 startIndex 移动到了 A。旧节点的 startIndex 和 endIndex 都保持不动
第四次循环中,发现了新旧节点的开头(都是 A)相同,于是 diff 后创建了 A 的真实节点,插入到前一次创建的 E 节点后面。同时旧节点的 startIndex 移动到了 B,新节点的 startIndex 移动到了 B
第五次循环中,情形同第四次循环一样,因此 diff 后创建了 B 真实节点 插入到前一次创建的 A 节点后面。同时旧节点的 startIndex 移动到了 C,新节点的 startIndex 移动到了 F
新节点的 startIndex 已经大于 endIndex 了,需要创建 newStartIdx 和 newEndIdx 之间的所有节点,也就是节点F,直接创建 F 节点对应的真实节点放到 B 节点后面
小结
-
当数据发生改变时,订阅者
watcher就会调用patch给真实的DOM打补丁 -
通过
isSameVnode进行判断,相同则调用patchVnode方法 -
patchVnode做了以下操作:- 找到对应的真实
dom,称为el - 如果都有都有文本节点且不相等,将
el文本节点设置为Vnode的文本节点 - 如果
oldVnode有子节点而VNode没有,则删除el子节点 - 如果
oldVnode没有子节点而VNode有,则将VNode的子节点真实化后添加到el - 如果两者都有子节点,则执行
updateChildren函数比较子节点
- 找到对应的真实
-
updateChildren主要做了以下操作:- 设置新旧
VNode的头尾指针 - 新旧头尾指针进行比较,循环向中间靠拢,根据情况调用
patchVnode进行patch重复流程、调用createElem创建一个新节点,从哈希表寻找key一致的VNode节点再分情况操作
- 设置新旧