Vue的diff算法
前言
本文我们总结一下有关 diff 算法的相关内容和实现原理。
diff 算法可以看作是一种对比算法,对比的对象是新旧虚拟 Dom。顾名思义,diff 算法可以找到新旧虚拟 Dom 之间的差异,但 diff 算法中其实并不是只有对比虚拟 Dom,还有根据对比后的结果更新真实 Dom。
算法的复杂度优化
两个树的完全的 diff 算法是一个时间复杂度为 O(n3) , Vue 进行了优化·O(n3) 复杂度的问题转换成 O(n) 复杂度的问题(只比较同级不考虑跨级问题),因为在前端操作 dom 的时候了,不会把当前元素作为上一级元素或下一级元素,很少会跨越层级地移动 Dom 元素,常见的都是同级的比较。 所 以 Virtual Dom 只会对同一个层级的元素进行对比。
原理
在数据发生变化,vue是先根据真实DOM生成一颗 virtual DOM ,当 virtual DOM 某个节点的数据改变后会生成一个新的 Vnode ,然后 Vnode 和 oldVnode 作对比,发现有不一样的地方就直接修改在真实的DOM上,然后使 oldVnode 的值为 Vnode ,来实现更新节点。
- 先去同级比较,然后再去比较子节点
- 先去判断一方有子节点一方没有子节点的情况
- 比较都有子节点的情况
- 递归比较子节点

源码总结
在进行节点比较时,是通过 patch 这个方法实现,其中如果不是真实元素并且用 sameVnode 看两个是否是同一个元素,如果是然后会调用 patchVnode 进行比较,比较的是虚拟节点不是真实节点,如果不值得去比较则用 Vnode 替换 oldVnode。
patchVnode 会比较这两个节点,判断 Vnode 和 oldVnode 是否指向同一个对象,如果是,那么直接 return,复用老的真是元素,如果不是会用新的子节点和旧的字节做比较。
如果他们都有文本节点并且不相等,那么将 el 的文本节点设置为 Vnode 的文本节点。
如果两个都有子节点的情况下会调用 updateChildren 方法比较他们的子节点。
只有新的节点有子节点而旧节点没有子节点,就会把新增的子节点插入到旧的dom中。
如果当前新的节点中没有子节点,旧的中有子节点,然后就会把旧的节点删除掉。
updateChildren 方法中,先定义了四对指针,先比较新的和旧的第一个子节点是否一样,如果一样会移动前面两个指针,以此类推,如果比对最后新的节点多了一个子节点就把它插入旧的中。
如果开始第一个子节点不一样就从后面开始进行比较(从尾子节点开始比较),比到最后把新增的节点插入到旧的 dom 中。
还有这种情况就是头和尾节点都不相等的情况下,用当前的头和旧的尾节点进行比较,如果一样就把旧的尾节点移到前面去,然后将旧的尾指针向前移动一位,当前头指针移动到下一个子节点上。
另一种就是用旧的结尾和新的开头节点进行比较,四种比较策略。
如果存在key,就会拿的当前子节点的key去旧的子节点中找,如果找到就将它移动到旧节点的前面,然后就将指针移向当前节点的第二个子节点上,以此类推,如果当前子节点没有就将它直接插入到旧的节点中,最后把旧的节点中多余出的子节点删除掉。
patch
1 | return function patch (oldVnode, vnode, hydrating, removeOnly) { |
patchVnode
1 | function patchVnode ( |
updateChildren
1 | function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) { |
最后
本文转载自 csdn https://blog.csdn.net/qq_42072086/article/details/107965196,作者为 王三六
Vue的diff算法

