【框架对比】React和Vue的diff算法

·  阅读 7237

此篇抽象对比了两框架diff算法,有时间深入研究react diff算法逻辑,不然理解欠深

后续会从各角度对比React和Vue,除了此文,目前已有的:

【框架对比】React和Vue的通讯方式

【框架对比】React和Vue的生命周期

【框架对比】React和Vue的hook函数

虚拟DOM对象包含以下属性:

  • sel:选择器
  • data:绑定的数据(attribute/props/eventlistner/class/dataset/hook)
  • children:子节点数组
  • text:当前text节点内容
  • elm: 对真实dom element的引用
  • key:用于优化DOM操作

diff算法比较变量

vue维护四个变量:

  • oldStartIdx => 旧头索引
  • oldEndIdx => 旧尾索引
  • newStartIdx => 新头索引
  • newEndIdx => 新尾索引

两边方向同时比较,由新的位置来获取真实DOM;如果老的先走完,就添加;如果新的先走完,就删除

react维护三个变量:

  • nextIndex => 遍历nextChildren时候的index,每遍历一个元素加1 (遍历新节点)
  • lastPlacedIndex => 上一次从prevChildren中取出来元素时,这个元素在prevChildren中的index(新节点对应)
  • oldIndex => 元素在数组中的位置(旧节点对应的位置)

节点移动前提是:oldIndex < lastPlacedIndex

移动的原则:

  • 首个节点(指的是新节点)不执行移动操作(除非它要被移除),以该节点为原点,其它节点都去寻找自己的新位置;
  • 将原来的元素往右移,通过lastIndex来控制。在lastIndex左边的,就往lastIndex右边移动;在lastIndex右边的,就不需要动。

nextIndex : 往右遍历,逐渐+1

oldIndex:根据nextIndex在旧结点中寻找对应的元素,如果能找到比较oldIndex和lastPlacedIndex,否则添加

lastPlacedIndex:可以理解为是一个比较指引,当发生移动的时候lastPlacedIndex值保持上一次比较值,不做移动使用oldIndex值

oldIndex = 4 > lastPlacedIndex 不做操作,且 lastPlacedIndex = oldIndex = 4

oldIndex = 0 < lastPlacedIndex 移动, lastPlacedIndex保持不变

diff算法比对方式

  1. vue的列表比对,采用从两端到中间的比对方式,而react则采用从左到右依次比对的方式。当一个集合,只是把最后一个节点移动到了第一个,react会把前面的节点依次移动,而vue只会把最后一个节点移动到第一个。总体上,vue的对比方式更高效。

  2. vue比对节点,当节点元素类型相同,但是className不同,认为是不同类型元素,删除重建,而react会认为是同类型节点,只是修改节点属性

react只比较节点类型和key

function sameVnode(vnode1: VNode, vnode2: VNode): boolean {
  return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel;
}
复制代码

vue比较节点类型和key,还有属性

function sameVnode (a, b) {
  return (
    a.key === b.key &&  // key值
    a.tag === b.tag &&  // 标签名
    a.isComment === b.isComment &&  // 是否为注释节点
    // 是否都定义了data,data包含一些具体信息,例如onclick , style
    isDef(a.data) === isDef(b.data) &&  
    sameInputType(a, b) // 当标签是<input>的时候,type必须相同
  )
}
复制代码

diff算法遍历原理

  1. React 首位是除删除外是固定不动的,然后依次遍历对比;

  2. Vue 的compile 阶段的optimize标记了static 点,可以减少 differ 次数,而且是采用双向遍历方法;

diff算法跟新DOM逻辑

  1. Vue基于snabbdom库,它有较好的速度以及模块机制。Vue Diff使用双向链表,边对比,边更新DOM。

  2. React主要使用diff队列保存需要更新哪些DOM,得到patch树,再统一操作批量更新DOM。

相同点

  1. 虚拟DOM在比较时只比较同一层级节点,复杂度都为 O(n),降低了算法复杂度;

  2. 都使用key比较是否是相同节点,都是为了尽可能的复用节点

  3. 都是操作虚拟DOM,最小化操作真实DOM,提高性能(其实虚拟DOM的优势 并不是在于它操作DOM快)

  4. 都是不要用 index作为 key

www.sohu.com/a/406399943…

juejin.cn/post/684490…

juejin.cn/post/684490…

juejin.cn/post/684490…

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改