patch概念

在vue update的过程中,在遍历子代vnode的过程中,会用不同的patch方法来patch新老vnode,如果找到对应的newVnode和oldVnode,就可以直接复用里面的真实dom节点,避免重复创建元素带来的性能开销。

patch的过程中,如果当前vnode存在很多children的情况,那么需要分别遍历patch新的children vnode和老的children vnode

存在children的vnode类型

  • element元素类型vnode
<div>
   <span> 苹果 </span> 
   <span> 香蕉 </span>
   <span> 鸭梨 </span>
</div>

在vue3.0的源码中,patchElement用于处理element类型的vnode

  • flagment碎片类型vnode

创建一个vue组件时,只能有一个根节点,

<template>
   <span> 苹果 </span> 
   <span> 香蕉 </span>
   <span> 鸭梨 </span>
</template>

如上面,如果这样写就会报错,因为vue组件需要绑定一个单一的dom元素

flagment出现就像一个普通的dom元素,但他是虚拟的,不会在dom树种呈现

 <Fragment>
   <span> 苹果 </span> 
   <span> 香蕉 </span>
   <span> 鸭梨</span>
</Fragment>

在vue3.0的源码中,processFragment用于处理Fragment类型的vnode

diff的作用就是在patch子vnode过程中,找到与新vnode对应的老vnode,复用真实的dom节点,避免不必要的性能开销。

  • Diff策略

1.按照tree层级进行diff

2.按照类型进行diff

(1)不同类型的节点之间往往差异性很大,为了提升效率,只会对相同类型的节点进行diff

(2)不同类型会直接创建新类型节点,替换旧类型节点
3.列表diff

给列表元素设置key,可以提升效率

(1)通过老节点的key找到对应的新节点的index:遍历老的节点,判断有没有key,如果存在key,通过新节点的keyToNewIndexMap找到新节点的index,如果不存在key那么会遍历剩下的新节点试图找到对应的index

(2)如果存在index证明有对应的老节点,那么直接复用老节点进行patch,没有找到与老节点对应的新节点,就删除当前的老节点。

v-for种的key的作用:通过判断newVnode和oldVnode的key是否相等,从而复用与新节点对应的老节点,节约性能的开销。

                                 利用唯一的id作为key值

vue2.0的diff算法(头尾部各有两个指针进行比较)

vue3.0的diff算法(最长递增子序列来比较差异)

// c1: a b [ c d e ] f g  
// c2: a b [ d e c h ] f g
  • 从头对比找到有相同的节点patch,发现不同,立即跳出
  • 如果第一步没有patch完,立即从后往前开始patch,如果发现不同立即跳出循环
  • 如果新的节点数大于老的节点数,对于剩下的节点全部以新的vnode处理(这说明已经patch完相同的vnode)
  • 对于老的节点大于新的节点的情况,对于超出的节点全部卸载(这说明已经patch完相同的vnode)
  • 不确定的元素(这种情况说明没有patch完相同的vnode)与上两种情况成对立关系

 

 

Logo

前往低代码交流专区

更多推荐