vue diff算法
patch概念在vue update的过程中,在遍历子代vnode的过程中,会用不同的patch方法来patch新老vnode,如果找到对应的newVnode和oldVnode,就可以直接复用里面的真实dom节点,避免重复创建元素带来的性能开销。patch的过程中,如果当前vnode存在很多children的情况,那么需要分别遍历patch新的children vnode和老的children v
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)与上两种情况成对立关系
更多推荐
所有评论(0)