什么是diff算法
diff算法是一种通过同层的树节点进行比较的高效算法,避免了对树进行逐层搜索遍历,所以时间复杂度只有0。diff算法在很多场景下都有应用,例如在vue虚拟dom渲染成真实dom的新旧VNode节点比较更新时,就用到了该算法。
diff算法有两个比较显著的特点:比较只会在同层级进行,不会跨层级比较。在diff比较的过程中,循环从两边向中间收拢。
Vue2的diff算法
1、核心原理
- 同级比较:只比较同一层级的节点,不跨层级比较。
- 两端比较:Vue2的Diff算法采用双端比较策略,从列表的两端(头部和尾部)开始比较,以尽量减少节点的异动次数。
- 更新策略: 当头尾比较无法匹配时,Vue2会尝试复用旧节点,通过更新节点的属性或子节点来匹配新的虚拟节点,同时将其移动到正确的位置,以减少DOM操作次数。
- 静态节点优化: 对于静态节点,Vue2在构建虚拟Dom树时会有一些优化,但在更新时,这些优化不会重复利用。
2、diff流程
- 当一组老节点发生了变化,新节点如何通过diff算法与老节点对比的呢
let oldStartIdx = 0 // 老vnode遍历的开始下标
let newStartIdx = 0 // 新vnode遍历的开始下标
let oldEndIdx = oldCh.length - 1 // 老vnode列表长度
let oldStartVnode = oldCh[0] // 老vnode列表第一个子元素
let oldEndVnode = oldCh[oldEndIdx] // 老vnode列表最后一个子元素
let newEndIdx = newCh.length -1 // 新vnode列表长度
let newStartVnode = newCh[0] // 新vnode列表第一个子元素
let newEndVnode = newCh[newEndIdx] // 新vnode列表最后一个子元素
- diff比较前端的代码初始化就完成了,接下来进行循环节点遍历
- 循环过程中首先对新老vnode节点的头尾进行比较,寻找相同节点,如果有相同节点满足sameVnode(可以服用的相同节点)则直接进行patchVnode(该方法进行节点复用处理),并且根据情形,移动新老节点的VNode索引,以便进行下一次循环处理,一共有2*2=4种情形。
- 情形1:当新老VNode节点的start满足sam