diff 算法是一种通过同层的树节点进行比较的高效算法,避免对树的逐层遍历,减少时间复杂度。
diff 算法的两个特点:
Vue的虚拟 dom diff 核心在于 patch 过程
let oldStartIndex = 0;
let oldEndIndex = oldChildren.length - 1;
let oldStartVnode = oldChildren[0];
let oldEndVnode = oldChildren[oldEndIndex];
let newStartIndex = 0;
let newEndIndex = newChildren.length - 1;
let newStartVnode = newChildren[0];
let newEndVnode = newChildren[newEndIndex];
第一步:
创建四个指针,分别为旧 Vnode 的开始指针和结束指针,新 Vnode 的开始指针和结束指针。第二步:
先比较旧 Vnode 的开始指针和新 Vnode 的开始指针,即A
和E
,发现不是同一个节点。第三步:
再比较旧 Vnode 的结束指针和新 Vnode 的结束指针,即D
和F
,依然不是相同节点。第四步:
再比较旧 Vnode 的开始指针和新 Vnode 的结束指针,即A
和F
,不是相同节点。第五步:
再比较旧 Vnode 的结束指针和新 Vnode 的开始指针,即E
和D
,不是相同节点。第六步:
通过上述四种对比方式都不是相同节点,下面就在旧 Vnode 节点中查找是否有与E
节点相同的节点。第七步:
发现旧 Vnode 节点中没有E
节点,那么就会在旧 Vnode 开始指针前插入一个新的E
节点。第八步:
第一个节点操作完后,指针后移,继续进行比较,重复第二至第七步,结果为新增、删除、移动。第九步:
当找到相同节点时,会通过patchVnode
进行这两个节点更细致的diff
。每次diff都会调用updateChildren
方法来比较,然后层层递归下去,直到将旧Vnode和新Vnode中的所有子节点对比完。domDiff的过程更像是两个树的比较,每找到相同节点时,都会一层层的往下比较它们的子节点,是一个深度递归遍历比较的过程。