12-Vue的diff算法

news2024/12/23 20:15:21

参考回答:

当组件创建更新时,vue均会执行内部的update函数,该函数使用render函数生成的虚拟dom树,将新旧两树进行对比,找到差异点,最终更新到真实dom
对比差异的过程叫diff,vue在内部通过一个叫patch的函数完成该过程
在对比时,vue采用深度优先、同层比较的方式进行比对。
在判断两个节点是否相同时,vue是通过虚拟节点的keytag来进行判断的
具体来说,首先对根节点进行对比,如果相同则将旧节点关联的真实dom的引用挂到新节点上,然后根据需要更新属性到真实dom,然后再对比其子节点数组;如果不相同,则按照新节点的信息递归创建所有真实dom,同时挂到对应虚拟节点上,然后移除掉旧的dom。
在对比其子节点数组时,vue对每个子节点数组使用了两个指针,分别指向头尾,然后不断向中间靠拢来进行对比,这样做的目的是尽量复用真实dom,尽量少的销毁和创建真实dom。如果发现相同,则进入和根节点一样的对比流程,如果发现不同,则移动真实dom到合适的位置。
这样一直递归的遍历下去,直到整棵树完成对比。

1. diff 的时机

当组件创建时,或依赖的属性或数据变化时,会运行一个函数,该函数会做两件事:

  • 运行 _render 生成一棵新的虚拟dom树(vnode tree)
  • 运行 _update,传入虚拟dom树的根节点,对新旧两棵树进行对比,最终完成对真实dom的更新

核心代码如下:

// vue构造函数
function Vue(){
    // ... 其他代码
    var updateComponent = () => {
    this._update(this._render())
    }
    new Watcher(updateComponent)
    // ... 其他代码
}

diff就发生在_update函数的运行过程中

2. _update 函数在干什么

_update函数接收到一个vnode参数,这就是生成的虚拟dom树

同时,_update函数通过当前组件的_vnode属性,拿到的虚拟dom树

_update函数首先会给组件的_vnode属性重新赋值,让它指向新树

function update (vnode) {
		// vnode 新
		// this._vnode  旧
	let oldVnode = this._vnode;
	this._vnode = vnode;
	// 对比的目的:更新真实dom
	if (!oldVnode) {
		this.__patch__(this.$el.vnode);
	}
}

然后会判断旧树是否存在:

  • 不存在:说明这是第一次加载组件,于是通过内部的patch函数,直接遍历新树,为每个节点生成真实DOM,挂载到每个节点的elm属性上
  • 存在:说明之前已经渲染过该组件,于是通过内部的patch函数,对新旧两棵树进行对比,以达到下面两个目标:

  • 完成对所有真实dom的最小化处理

  • 让新树的节点对应合适的真实dom

3. patch 函数的对比流程

术语解释

  1. 相同」:是指两个虚拟节点的标签类型、key值均相同,但input元素还要看type属性
  2. 新建元素」:是指根据一个虚拟节点提供的信息,创建一个真实dom元素,同时挂载到虚拟节点的elm属性上
  3. 销毁元素」:是指:vnode.elm.remove()
  4. 更新」:是指对两个虚拟节点进行对比更新,它仅发生在两个虚拟节点「相同」的情况下。具体过程稍后描述。
  5. 对比子节点」:是指对两个虚拟节点的子节点进行对比,具体过程稍后描述

详细流程:

  1. 根节点比较

patch函数首先对根节点进行比较

如果两个节点:

  • 「相同」,进入**「更新」流程**
  1. 将旧节点的真实dom赋值到新节点:newVnode.elm = oldVnode.elm

  2. 对比新节点和旧节点的属性,有变化的更新到真实dom中

  3. 当前两个节点处理完毕,开始**「对比子节点」**

  • 不「相同」
  1. 新节点递归「新建元素」

  2. 旧节点「销毁元素」

  3. 「对比子节点」

在「对比子节点」时,vue一切的出发点,都是为了:

  • 尽量啥也别做
  • 不行的话,尽量仅改动元素属性
  • 还不行的话,尽量移动元素,而不是删除和创建元素
  • 还不行的话,删除和创建元素

本文转载自:

94.diff · 工作常见问题 · 看云

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/716982.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT系统源码,全开源支持二开!

ChatGPT是开发的大语言模型之一,具备多领域知识,并且可以提供个性化、准确和有趣的答案,无论是在娱乐、教育还是工作中,都可以帮助我们解决问题、获取信息和提供建议。 技术架构 使用流行的技术栈PHP8、TypeScript、ThinkPHP6、…

7.3基础概念/文件、文件路径/batch_size,length,total/acc、loss计算/ect

一、 一些基础术语: util是utility的缩写,意思为实用工具。一般用于描述和业务逻辑没有关系的数据处理分析工具。 logger :日志 meter : 记录表 使用下划线 _ 表示不需要的变量是一种常见的开发者的约定,(Python 解释…

SpringBoot3 事件和监听器

1. 生命周期监听 场景:监听应用的 生命周期 1. 监听器-SpringApplicationRunListener 自定义SpringApplicationRunListener来监听事件; 编写SpringApplicationRunListener 实现类在 META-INF/spring.factories 中配置 org.springframework.boot.SpringA…

【数据挖掘】时间序列教程【八】

4.4 时间混淆 我们先考虑一个简单的线性回归模型, 哪里 和是具有平均值的高斯过程00和自协方差 .现在,在不失去一般性的情况下,让我们假设 而那瓦尔

【UGUI控件全面解析】 教程专栏目录贴

🎬【UGUI控件全面解析】 教程专栏目录贴🐱‍🏍UGUI系列内容介绍🎁文章内容结构介绍 💯总结 🎬 博客主页:https://xiaoy.blog.csdn.net 🎥 本文由 呆呆敲代码的小Y 原创,…

“金九银十”和秋招通过率达 95% 的 Java 面试要点集锦

前言 这才刚刚进入 7 月,我就看到了许多朋友在焦急的准备“金九银十”跳槽面试,甚至很多即将毕业的大学生都在备战秋招,对于学历还算优秀的大学生来说,这是一次离大厂最近的机会,毕竟是应届毕业生,不会对技…

Selenium Wire编辑header破解反爬机制和访问限制

一、selenium Wire介绍 介绍 Selenium Wire扩展了Selenium的Python绑定,使您能够访问浏览器发出的底层请求。您已使用Selenium相同的方式编写代码,但是您获得了额外的api,用于检查请求和响应,并动态地对它们进行更改。&#xff08…

oracle 基础1

目录 Oracle表空间-创建 Oracle表空间-删除 Oracle常用用户 Oracle常用角色 Oracle用户创建 Oracle常用数据类型 Oracle表创建 Oracle增删改查 Oracle表常见约束 0.oracle手动开启方式 1.Oracle 表空间-创建 plsql登录system用户 新建sql窗口 创建表空间 2.Oracle表…

化亿级海量于秒级瞬间:大表关联计算提速

5G 时代,意味着数据通信将会拥有更高的速率、更大的容量和更低的时延。随着数据量的爆发式增长,对海量数据存储和实时分析成为数据淘金者的刚需,数据量暴增导致数据间的关联分析也越来越频繁。如何快速对数据进行分析,并获取其中有…

Jmeter接口测试参数化详解

目录 前言: RandomString函数 CSVRead函数 CSV Data Set Config配置元件 前言: 在进行接口测试时,参数化是一项重要的技术,可以帮助测试人员有效地模拟不同的场景和数据,增加测试用例的覆盖范围。JMeter提供了多种…

2023 年 10 大前端发展趋势

新技术的出现和老技术的淘汰让前端开发者们需要不断地学习和更新知识。特别是在经济不好的情况下,是否掌握新的技术很大程度决定着你是否被淘汰。 虽然应用程序试图将网站替代,但前端 Web 开发业务仍在快速变化和增长,前端开发人员的功能并没…

Debezium系列之:支持数据库存储系统,把ddl信息存储到数据库表中

Debezium系列之:支持数据库存储系统,把ddl信息存储到数据库表中 一、需求背景二、实现的效果三、核心参数四、创建存储ddl表五、创建采集表六、完整配置七、提交connector八、插入数据九、查看ddl数据十、修改表结构十一、清空存储ddl表十二、总结和延展一、需求背景 目前deb…

基于transformer的人群计数论文汇总

文章目录 2022TransCrowd: weakly-supervised crowd counting with transformersAn End-to-End Transformer Model for Crowd Localization 参考 2022 TransCrowd: weakly-supervised crowd counting with transformers code: https://github.com/dk-liang/TransCrowd 摘要&a…

达梦数据库性能分析

目录 数据库常用性能分析方法... 3 一、服务器监控... 3 1、cpu监控... 3 2、内存... 3 3、swap内存... 3 4、磁盘... 4 5、网络监测... 4 二、数据库实例监控... 6 1、v$sessions. 6 2、慢sql、阻塞、锁... 7 3、内存监控... 10 4、monitor监控工具使用及开启sql日…

五年Java学习心路历程

五年Java学习心路历程 从大学毕业到工作的过程中,我度过了五年学习Java的岁月。从基础语法到各种细节技术再到分布式和微服务架构,经历了许多的挑战与成长。接下来,我将详细记录这段心路历程,与大家分享学习Java的经验与感悟。 …

Java基础---String str=new String(“tang“)创建了几个对象

目录 典型回答 常量池基本概念 字符串常量池的结构 再看字面量和运行时常量池 intern 还是创建了几个对象 intern的正确用法 典型回答 创建的对象数应该是1个或者2个如果常量池中存在,则直接new一个对象如果常量池不存在,则在常量池中创建一个对象…

KubeEdge官方示例运行成功_Counter Demo 计数器

运行KubeEdge官方示例_Counter Demo 计数器 KubeEdge Counter Demo 计数器是一个伪设备,用户无需任何额外的物理设备即可运行此演示。计数器在边缘侧运行,用户可以从云侧在 Web 中对其进行控制,也可以从云侧在 Web 中获得计数器值,原理图如下…

前端web入门-移动web-day10

(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 移动Web基础 手机模拟器 屏幕分辨率 视口 二倍图 适配方案 rem 适配方案 rem 媒体查询 rem – …

使用java生成mvt切片的方法

如何使用java生成geoserver的矢量切片供前端(mapbox等)调用 目录新的想法Java能为切片做什么如何生成切片如何转换xyz数据如何查询如何输出mvt格式给前端前端如何调用 目录 好久没发博客了,每日或忙碌、或悠闲、或喜或悲、时怅时朗&#xff…

访问学者怎样准备申请推荐信

作为访问学者,申请推荐信是非常重要的一步,它能够在您的申请过程中增加信誉度和竞争力。一个优秀的推荐信可以更好地展现您的学术能力、研究潜力和个人品质。以下是知识人网小编整理的关于如何准备申请推荐信的建议: 1. 确定推荐人&#xff1…