- 在使用Diff算法比较两个节点的时候,只会在同层级进行比较,而不会跨层级比较(也就是说只会在拥有相同爸爸的子节点中进行对比)。
这次我们先说结论,两者有什么区别
1、children节点对比时,React是从左到右遍历对比,vue是从双端交叉进行对比;
2、Vue的整体效率会比React高一些,比方说这个场景下:加入有多个子节点,我只是把最后一个节点移到了第一个
①React是需要借助 Map来匹配key,再复用节点;
②Vue会发现移动,直接去复用节点;
Vue diff
patchVnode
- 相同节点就调用
patchVnode(oldVnode, vNode)
,下图是它的流程:
- 除了比较子节点的方法
updateChildren(elm, oldCh, ch)
与React不同,其余都差不多,都是从根节点属性、文本节点、孩子节点比较下来的;
updateChildren(elm, oldCh, ch)
- 它就是Vue diff的核心了,【双端交叉对比法】,首先这个方法传入三个比较重要的参数,即parentElm父级真实节点;oldCh为oldVnode的孩子节点;newCh为Vnode的孩子节点。
- 它每次按照下面5个步骤,来移动四个指针,直到有一组指针重叠并越过,则对比结束;
①头头对比;②尾尾对比;③旧头新尾对比;④旧尾新头对比;⑤通过key值对比; - 同样,找到相同的节点就调用
patchVnode(oldVnode, vNode)
,对这个节点进行patch;
React diff
1、首先对比两棵树的根节点
i. 如果根节点的类型改变了,比如 div 变成了 p,那么直接认为整棵树都变了,不再对比子节点。此时直接删除对应的真实 DOM 树,创建新的真实DOM 树。
ii. 如果根节点的类型没变,就看看属性变了没有
a. 如果没变,就保留对应的真实节点
b. 如果变了,就只更新该节点的属性,不重新创建节点。
2、然后同时遍历两棵树的子节点,从左到右遍历对比(这就是与vue的双端交叉对比不同的地方),每个节点的对比过程同上。
ⅰ. 当子节点上都没有key的时候,那么每个节点的对比过程与跟节点的对比过程一致;
ⅱ. 当子节点上有key的时候
它会把变化的那个节点以及后面的节点全部暂存在map里,后面的节点就先从桶里进行key的匹配,没有匹配到的节点就创建它,匹配到就复用,有key剩下来了就删除它;
对于key的用途
- key在vue和react中的用途是一致的,都是为了给元素绑定一个唯一的标识,用于判断元素是新创建的还是被移动的元素,从而减少不必要的DOM渲染;
- key值一般不要用index来辨识,最好用唯一的id值来标识;因为如果用index做key值,那么修改list后,随着页面的重新渲染,key值可能就会发生变化,那么我们就失去了使用key值的意义了;
- 但是!!当有很多分页的纯数据列表展示页面时,用index做key值会好一些,这样每页的元素都不需要销毁重建了,可以直接复用;