Vue2 的 diff 算法原理

diff 的时机

当组件创建、以及依赖的属性或数据变化从而运行_update()函数时。

_update 的作用

  1. 接收一个vnode参数,即新的 vnode。
  2. 同时通过当前组件的_vnode属性拿到旧的 vnode。
  3. 将新的 vnode 赋值给 _vnode 属性。
  4. 判断旧的 vnode 是否存在:
    • 不存在则调用patch函数遍历新的 vnode 为每个节点创建真实 DOM,并挂载到每个节点的ele属性上。
    • 存在则通过 patch 函数对新旧 vnode 进行对比,让新 vnode 的每个节点的 ele 属性匹配到合适的真实 DOM,并以最小代价完成真实 DOM 处理。

patch 函数的运行流程

主要是通过同时满足以下 3 个条件判断两个虚拟节点是否相同(相同三要素):

  1. 标签类型tag是否相同
  2. key值是否相同
  3. 如果是 input 元素, type 属性是否相同

对比过程总结为深度优先,同层对比,即先将当前节点及其子节点对比完,再从同层节点寻找下个对比对象,详细流程:

  1. 根节点比较

    • 若相同,则开始更新,将旧节点的真实 dom 赋值给新节点的 ele 属性,对比新旧节点的属性,将变化更新到真实 dom 中,当前两个节点处理完毕后开始对比子节点。
    • 若不相同,则新节点递归创建真实 dom,旧节点销毁 ele 属性,即销毁旧的真实 dom。
  2. 对比子节点,大致与上述对比相同,通过以下方面进行对比效率提升

    • 优先只改动真实 dom 元素属性
    • 其次移动元素以替代创建和删除元素
    • 最后才考虑创建和删除元素

子节点对比细节

vue 对新旧 vnode 生成了新旧两个子节点数组,并对两个数组同使用两个指针,分别指向各自数组的头和尾,然后不断向数组中间靠拢来一一对比:

若新旧数组的头或尾指针所指向的节点相同(相同三要素),则只改动真实 dom 元素的属性差异,同时当前两个指针移动。

若不同则从旧数组中寻找所有与当前新数组头指针相同的节点,若还没找到,则创建元素,同时新数组头或尾指针移动,进行下一轮对比...当新数组头指针超过尾指针,循环结束,没有被匹配到的旧数组会被遍历删除元素。

就这样一直递归遍历下去,直到整颗新的 vnode tree 对比完成,之后旧的 vnode 所占用的内存空间则会被垃圾回收。

相关推荐
前端大波3 分钟前
使用webpack-bundle-analyzer 对 react 老项目进行打包优化
前端·react.js·webpack·性能优化
前端 贾公子10 分钟前
(catalog协议) == pnpm (5)
前端·javascript·react.js
JarvanMo15 分钟前
深度解析:如何彻底终结 Flutter 异步操作中的 BuildContext 崩溃?
前端
wxr061620 分钟前
部署Spring Boot项目+mysql并允许前端本地访问
前端·spring boot·mysql·持续部署
假装我不帅26 分钟前
jquery-validation使用
前端·javascript·jquery
怕浪猫31 分钟前
React从入门到出门第六章 事件代理机制与原生事件协同
前端·javascript·react.js
天府之绝34 分钟前
uniapp 中使用uview表单验证时,自定义扩展的表单,在改变时无法触发表单验证处理;
开发语言·前端·javascript·vue.js·uni-app
be or not to be36 分钟前
Html-CSS动画
前端·css·html
初恋叫萱萱41 分钟前
技术基石与职场进阶:构建从Web后端到高性能架构的完整知识图谱
前端·架构·知识图谱
木木木一1 小时前
Rust学习记录--C9 错误处理
前端·学习·rust