vue中的dom diff算法
#
一、Diff算法Diff算法是种通过同层的树节 点进行比较的高效算法,避免对树的逐层遍历, 减少时间复杂度。diff算法在很多场景 下都有用,比如vue 虚拟dom 渲染生成真实dom的新旧VNonde比较更新。
diff算法两个特点:
- 只会同级比较,不跨层级
- diff比较循环两边往中间收拢,
#
二、Vue Diff算法vue的虚拟domdiff 核心在于patch 过程
#
2.1首先将新旧VNode进行开始位置和结束位置的标记let oldStartIndex = 0;let oldEndIndex = oldChildren.length - 1;let oldStartVnode = oldChidren[0];let oldEndVnode = oldChildren[oldEndIndex];let newStartIndex = 0;let newEndIndex = newChildren.length - 1;let newStartVnode = newChildren[0];let newEndVnode = newChildren.length;
#
2.2标记好节点位置,进行循环处理节点- 如果当前oldStartVnode和newStartVnode节点相同,直接用新节点复用老节点,进行patchVnode 复用,更新oldStartVnode, newStartVnode, oldStartIndex++和newStartIndex++
- 如果当前oldEndVnode 和newEndVnode 节点相同,直接用新节点复用老节点,进行patchVnode 复用,更新oldEndVnode, newEndVnode, oldEndIndex-- 和newEndIndex--
- 如果当前oldStartVnode和newEndVnode节点相同,直接用新节点复用老节点,进行patchVnode复用,将将老节点移动到oldEndVnode 节点之后,,更新 oldStartVnode, newEndVnode, oldStartIndex++ 和newEndIndex--
- 如果当前oldEndVnode和newStartVnode 节点相同,直接用新节点复用老节点,进行patchVnode复用,将复用老节点移动oldStartVnode 的elm之前,,更新 oldStartVnode, newEndVnode, oldEndIndex-- 和newStartIndex--
- 如果都不满足则没有相同节点复用,进行key的对比。满足条件进行patchVnode 过程,并将dom移动到oldStartVnode 对应真是dom之前。没找到则重新创
#
2.3递归处理#
三、Vue Diff 图解- 第一步:创建四个指针, 分别为旧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 的过程更像是两个树的比较,每找到相同节点时,都会层-层的往 下比较它们的子节点, 是一个深度递归遍历比较 的过程。