如有错误望大家指出,共同进步
diff算法
一种对比新旧虚拟dom的一种方法, 找出需要更改的虚拟节点并对其进行更新,其他没有更新的则不用改变
使用虚拟dom算法的损耗计算:总损耗 = 虚拟dom增删改+(与diff算法效率有关)真实dom增删改+(较少的节点)排版和重绘
直接操作真实dom的损耗计算:总损耗 = 真实dom完全增删改+(可能较多的节点的)排版和重绘
diff是深度优先算法,进行同层比较
流程:
当数据改变时,会触发setter,并且通过Dep.notify去通知所有订阅者Watcher,订阅者们会调用patch方法,给真实dom打补丁,更新相应的视图
vue的diff算法
patch方法:
对比当前同层的虚拟节点是否为同一种类型的标签:
判断其是否是同一类型的标签的标准:
key值是否一样;标签名是否一样;是否都为注释节点;是否都定义了data;当标签是input时,type是否相同;
-
是:继续执行patchNode方法:
-
找到对应的真实dom,称为el
-
判断newNode和oldnode是否指向同一个对象,如果是,直接return
-
如果他们都有文本节点并且不相等,那么直接将el的文本节点设置为newVnode的文本节点
-
如果oldVnode有子节点而newVnode没有,则删除el的子节点
-
如果oldVnode没有子节点而newVnode有,则将newVnode的子节点真实化之后添加到el
-
如果两者都有子节点,则执行updateChildren函数比较子节点
updateChildren方法:新的子节点集合和旧的子节点的集合各有首尾两个指针
新旧节点首尾进行四次比较,如果四次都匹配不到,则将所有旧子节点的key做一个映射到旧节点下标的key=>index表,然后用新vnode的key去找出旧节点中可以复用的位置
-
-
否:没必要比对,直接整个节点替换成新虚拟节点
vue2与vue3的对比
- vue2中会将没有发生更改的节点进行比较,比较消耗性能;在vue3中,创建虚拟dom树的时候,会根据dom中的内容会不会发生变化添加静态标记,在之后的过程中比较这些带有静态标记的节点。
摘自原文blog.csdn.net/qq_45613931…
export const enum PatchFlags {
// 动态文本节点
TEXT = 1,
// 动态 class
CLASS = 1 << 1, // 2
// 动态 style
STYLE = 1 << 2, // 4
// 动态属性,但不包含类名和样式
// 如果是组件,则可以包含类名和样式
PROPS = 1 << 3, // 8
// 具有动态 key 属性,当 key 改变时,需要进行完整的 diff 比较。
FULL_PROPS = 1 << 4, // 16
// 带有监听事件的节点
HYDRATE_EVENTS = 1 << 5, // 32
// 一个不会改变子节点顺序的 fragment
STABLE_FRAGMENT = 1 << 6, // 64
// 带有 key 属性的 fragment 或部分子字节有 key
KEYED_FRAGMENT = 1 << 7, // 128
// 子节点没有 key 的 fragment
UNKEYED_FRAGMENT = 1 << 8, // 256
// 一个节点只会进行非 props 比较
NEED_PATCH = 1 << 9, // 512
// 动态 slot
DYNAMIC_SLOTS = 1 << 10, // 1024
// 静态节点
HOISTED = -1,
// 指示在 diff 过程应该要退出优化模式
BAIL = -2
}
- vue3中存在最长递增子序列使得我们可以保证移动次数最少
react的diff算法与vue的区别
- react在diff遍历的时候,只对需要修改的节点进行了记录,形成effect list,最后才会根据effect list进行真实的dom的修改,修改时先删除,然后更新和移动,最后插入
- vue在遍历的时候修改真实dom最后做删除操作
- react采用单指针从左到右进行遍历,vue采用双指针从两头向中间进行遍历
用index作为key的问题
vue中使用虚拟dom且根据diff算法进行新旧对比,从而更新真实dom,key是虚拟dom对象的唯一标识。
如果旧虚拟dom中找到了与新虚拟dom相同的key:
- 若虚拟dom中的内容没变,直接使用之前的真实dom
- 若虚拟dom中内容变了,则生成新的真实dom,随后替换掉页面中之前的真实dom
若对数据进行逆序添加,逆序删除等破i坏顺序操作:会产生没有必要的真实dom更新,页面效果没问题,但是效率低 如果结构中还包含输入类的dom:会产生错误dom更新=》界面有问题
如果不存在对数据的逆序添加或删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的 都会根据老的节点构建一个map,方便根据key快速查找
本文参考资料链接: juejin.cn/post/699495… juejin.cn/post/697837…