由浅入深读透vue源码:diff算法

news2025/1/11 23:50:19

42b7486c81f63fcf0cbedae3c90aa1be.gif导语 | 开发者工作中,研究代码逻辑常需要思考这个问题:数组变更后,具体变更了哪一些元素?变更的位置如何?本文作者陈碧松解析并覆写了针对数组变化的diff算法逻辑。希望本文对你有帮助。

bb6dd62fbd9dda7d72c9c97ac456aff6.jpegdiff方法的运行规则和前提方法

为了了解diff方法的运行规则和前提方法,首先我们通过几个图快速区别虚拟node进行深度优先和同级对比。

深度优先:

e46dae02db00e006f8dc337e087e9cb7.png

同级对比:

d63d9cf89d791ef1349cc4a37675736a.png

如上面图所示,每次vnode都是执行同级对比。(对应dom同一个父元素)

代码逻辑如下图:

13b21d4079edf340b352cfd368aa7119.png

第二,简单判断:`sameVnode`函数用来进行判断是否是同一个vnode元素。源代码如下:

0c798ef1e3b8a85da2b6f8c931a7fd17.png

如图所示:

fc779e29d2128d16f45bd8a2b56e992d.png

这里有两个重要元素:`key` : 开发者定义的”:key”;`sel `:  元素tagName+元素id+元素class。

sel的定义源码如下:

fa542ad883f9087e83040920b5e43459.png

vNode构建函数:

36e24f519e5de7876ac9fac88af83348.png

第三是构建索引。

e705115d5eb4cbc257c5ab0612ed0c1c.png

逻辑如图:

1a601f9de8805856c02e181a7de587d0.png

b39c57ba3262eca35f07d1de0f11a392.jpeg如何处理元素

尽量不新增/删除dom。如图下所示:

6bb810f80b8cc728b257cb38e51e4826.png

如果是相同vnode,源码如下:

c71a288eeb7facc1342d3b2b33924bd8.png

c35c94a88220ff454b327f4a0cc58def.jpeg开始比较

首先会进行时间复杂度O(n)的while循环,循环条件为“遍历旧节点数组&&遍历新节点数组,谁先遍历完循环就结束”。源码如下图:

0e3ac14f0c830e547a007be836e9403d.png

在每次的循环过程中,会有两大类判断方法:

1)首尾比较&首尾序号

ff06688b3617c33b30591d480e753d7c.png

逻辑:如图上所示。首先在循环遍历前标记好新,旧节点数组的开始位置和结束位置的序号:oldStartIdx、oldEndIdx、newStartIdx、newEndIdx;其次在循环遍历的过程中采用首首比较,尾尾比较,首尾比较"

源码如下:

564e04aa641138d2a856b4e6ba4c9bbc.png

如果数据为图上所示,那么根据首尾比较方法会有如下图所示结果,最终全部执行了更新操作:

177dd716afa33505782ad622e50792e4.png

2)索引比较

最坏情况,这里的时间复杂度也是O(n),即整个算法复杂度O(n)+O(n)。每次遍历的过程中可能存在"新数组节点新增/旧数组节点删除",那么前后对比就满足不了条件。这里逻辑会进入索引比较:比如这种情况:

a1ccd77f5537493b7581392ae487aba6.png

那么循环中会执行一遍,创建旧数组的索引对象。从创建到比较的整个逻辑图如下:

027d143d5e37865a5166ba0e19420390.png

这里的源码如下:

76a4ea392f53c22fd5d8ae968f6856a8.png

  • 当旧节点不存在新增的节点时,进行当前oldStartIdx位置的添加

    2289c3dc3640e4273a388c26bf1d7e07.png

源码如下:

24f2c9454351fc728bfbd67d89c92447.png

  • 当旧数组存在节点,那么进行位置移动

    994158a68f3f7b633b7cc764909420be.png

源码:

3f841124207d9478e5d484e72b251a1b.png

3)当节点遍历完之后

会存在两种情况:新数组已经遍历完,但旧数组没有遍历完成;旧数组遍历完成,但新数组没有遍历完成。故源代码的判断如下:

d4b200d0cbe3962c4b8e251f17f28805.png

  • 旧数组没有循环完成

旧数组没有循环完成的效果如下图所示:

9ae477e9ffebb685aa834d6639f7bf5f.png

这里注意一个点,我们每次的节点更新会移动序号,即使被删除的节点不在一块最终也会被首尾比较算法“摞在一块”(oldStartIdx~oldEndIdx)。上图所示更加明显。源码在这里就进行批量删除:

0a89b91736960476363dd440c3721618.png

  • 新数组没有循环完成

效果如下图所示:

9189e41d2f63471954d4426850899d1f.png

整体来说,有几个关键点:简单对比;创建旧数组的索引表;首位对比&首尾索引&vnode位置移动;索引添加/位移;剩余部分批量处理添加/删除

经过前后对比&索引的过滤后,只会存在新.末尾节点!==旧节点及之前的连续的新节点(!==旧节点),所以这里也被“摞在一块”,即 (newStartIdx~newEndIdx)。源码如下。这样,整个diff的对比算法就已经走完了。核心就是:前后对比+索引。

16eab893e386e5d390ff6b3645fa17a8.png

5995b87e1ee0e6a374833dfa49049df8.jpeg

vue3.0对于diff比较前的优化

vue3.0针对“无脑”patchVnode进行了过滤--静态类型Vnode老版的源码:

0b6678cda82b72d65ea2e7fe4be4e260.png

这里,我们再重复下vue2.x系列的对比更新逻辑:

db18ee9e51ff8d98238f4ccc016bc628.png

新版的vue3.0增加了静态类型Vnode。如果是静态类型的vnode,直接跳过更新,修改新节点引用即可。

8ce568f316e6f4678d0596f88887a963.png

comment类型目前翻到它的源码也只是更改引用,源码作者加上了一行注释。

85fa7716ffeacf65882c37594fb7bf50.png

补充一下,flagment碎片类型为新增的vnode类型,即:

cbaa8e16164c13096904ffef18817a58.png

vue3.0的过滤判断源码如下:

e49d80cd31f7d3f56d3f132a8e032e0e.png

db359b90d749b772bc698461bb26cfc4.jpeg

数组比较的应用

由于我们想监听数组的变化,参考了diff算法覆写类似的逻辑,用来在update,add,dels时,代码层面获取操作的具体节点明细(新旧节点的位置,内容)。希望本文对你有帮助。

你可能感兴趣的腾讯工程师作品

804869891be5481263803dedfb75bf67.png

736634e7b27b63d82966c9e553e43f47.png

| 优雅应对故障:QQ音乐怎么做高可用架构体系?

| 最全Go select底层原理,一文学透高频用法

| 十亿人都在用的健康码,运维体系是怎么设计的

详解全网最快Go泛型跳表【内附源码】

技术盲盒:前端后端AI与算法运维工程师文化

9c4784cdecd29db38d15411742608c8c.png

🔹关注我并点亮星标🔹

工作日晚8点 看腾讯技术、学专家经验

点赞|分享|在看 传递好技术

215945b24eb3219f6aeb479667b92ce8.png

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

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

相关文章

干货 | 医疗健康类APP违法违规个人信息收集的自动化检测技术研究

以下内容整理自清华大学《数智安全与标准化》课程大作业期末报告同学的汇报内容。第一部分:概述一、研究背景APP兴起在带给人们便利的同时,也在逐渐蚕食着人们的隐私边界。与此同时,“互联网医疗”使得医疗健康类APP兴起。二、研究目的本文旨…

Altium Designer 20 凡亿教育视频学习-05

第五部分学习 线距选择 焊盘与线之间的距离设置为为6mil 其他距离设置:如线与线之间的距离 Track--线的意思 copper--铜 via--过孔 SMD Pad--贴片焊盘 线宽选择 电源线需要加粗处理 操作1:专门为电源线制订规则 能专门为电源线制订宽度规则&…

基于STM32楼梯层控制系统

1、项目需求分析 项目目标意义: 随着社会的发展、 科技的进步以及人们生活水平的逐步提高, 各种方便于生活的遥控系统开始进入了人们的生活。 电梯的发展是由于需要从山坡上运输包括煤和材在内的原材料而引发的,而到了今日,电梯的…

JavaScript 注释

文章目录JavaScript 注释JavaScript 注释JavaScript 多行注释使用注释来阻止执行在行末使用注释JavaScript 注释 JavaScript 注释可用于提高代码的可读性。 JavaScript 注释 JavaScript 不会执行注释。 我们可以添加注释来对 JavaScript 进行解释,或者提高代码的可…

ArcGIS基础实验操作100例--实验59二维面转体模型

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台:ArcGIS 10.6 实验数据:请访问实验1(传送门) 高级编辑篇--实验59 二维面转体模型 目录 一、实验背景 二、实验数据 三、实验步骤 (1&am…

PyTorch简易安装方法(100%成功)

PyTorch简易安装方法(100%成功) 一般我们习惯用pip install xxx,同时使用清华源用来加速,这种方法安装99%的库都没啥大问题,但是有时候安装pytorch的时候就会发现问题。笔者反正每次用该方法安装torch总会遇到刚开始下…

活动星投票争做新时代好少年网络评选

“争做新时代好少年”网络评选投票_图文投票的便利_免费小程序广泛应用手机互联网给所有人都带来不同程度的便利,而微信已经成为国民的系统级别的应用。现在很多人都会在微信群或朋友圈里转发投票,对于运营及推广来说找一个合适的投票小程序能够提高工作…

【模拟CMOS集成电路】电路噪声——基本电路噪声性能(2)

【笔记:模拟CMOS集成电路】电路噪声——基本电路噪声性能(2)前言1 噪声——分析基础2 噪声——基本电路噪声性能2.1 MOS管噪声模型(1)电阻RG热噪声和沟道热噪声(2)衬底电阻热噪声(3)源极寄生电阻RS热噪声2.2常见组态的单级放大器噪声分析2.2.…

C++11基于范围的for循环vector容器扩容详解迭代器失效

目录 C11基于范围for循环 vector容器扩容详解 迭代器失效 总结 C11基于范围for循环 对于一个有范围的集合来说,在程序代码中指定循环的范围有时候是多余的,还可能犯错误。 为此C11中引入了基于范围的for循环。 语法: 语法:…

一加11:新的赛场,“不温和”的答卷

《不要温和地走进那个良夜》是英国诗人狄兰托马斯创作于20世纪中期的一首享誉世界的诗歌,作者所表达出的在逆境中坚韧不屈、逆流而上的精神,激励了一代又一代人。1月4日,一加11发布会现场,一加中国区总裁李杰Louis借鉴了狄兰托马斯…

联合证券|近90亿大资金“跑步入场”,光伏板块掀涨停潮

早盘光伏板块掀起涨停潮,原因或是这些。 国产特斯拉全线降价 1月6日,据特斯拉我国官网,特斯拉国产车型大幅降价,对国产Model 3后驱版、高性能版,及Model Y后驱版、长续航版、高性能版等五款车型进行调价。Model 3起价…

DFMN 代码解读

目录 0. 环境配置 1. 运行程序 2. 读代码的思路 1)model.py !! 关于继承 !! 关于网络结构组织 !! 关于 forward 2) 数据预处理 3)train.py 0. 环境配置 很简单,提示缺包xxx,pip install xxx 就可以了 1. 运行程序 从…

NuxtJS服务器端入门

一、搜索引擎优化 1、什么是SEO 总结:seo是网站为了提高自已的网站排名,获得更多的流量,对网站的结构及内容进行调整和优化,以便搜索引擎 (百度,google等)更好抓取到优质网站的内容&#xff0c…

GCN图神经网络和LSTM的介绍和使用场景 中英文

GCN-LSTM 可以学习参考 英文内容部分源自youtube的教学视频 自己跟着英文敲的 给定一辆出租车行驶时在某个时间段的速度,下一个时刻速度会是多少?这是一个时间序列回归预测问题。获得了若干时间点的速度,目标是预测出租车速度序列中的下一个…

线性模型:AR、MA、ARMA、ARMAX、ARX、ARARMAX、OE、BJ等

目录 1 AR 1 2 MA 1 3 ARMA 1 4 ARMAX 2 5 ARX 2 6 ARARX 3 7 ARARMAX 3 8 OE 3 9 BJ 3 各种线性模型,这些模型算数学基础模型,不仅在计量经济学,也在工业控制等各领域有应用。包括AR、MA、ARMA、ARMAX、ARX、ARARMAX、OE、BJ等。 1 AR 自…

【疑难攻关】——floor报错注入

作者名:Demo不是emo 主页面链接:主页传送门创作初心:舞台再大,你不上台,永远是观众,没人会关心你努不努力,摔的痛不痛,他们只会看你最后站在什么位置,然后羡慕或鄙夷座右…

mysql多表查询30个经典案例

mysql多表查询30个经典案例插入两张表一个dept一个emp插入dept表数据插入emp表数据1.列出每个部门里面有那些员工及部门名称;2.运维部门的收入总和;3.HR部入职员工的员工号4.财务部门收入超过5000元的员工姓名5.找出销售部收入最低的员工的入职时间;6.找…

5G NR标准: 第20章 5G的演进

第20章 5G的演进 NR 的第一个版本,第 15 版,侧重于对 eMBB 的基本支持,在某种程度上,URLLC.1 如前几章所述,第 15 版是为即将发布的 NR 未来发展构建的基础 . NR 演进将带来额外的功能并进一步提升性能。 附加功能不…

Netty原理示图

1. AWT事件驱动 2. Websocket协议 3. 基于多个反应器的多线程模式 4. Netty Reactor 工作架构图 5. Bootstrap引导过程 Channel Channel是Java NIO的基础。它表示一个开放的连接,进行IO操作。基本的 I/O 操作( bind() 、 connect() 、 read() 和 write(…

什么是异常?异常可以看作你敲出来的bug

异常异常的体系抛异常try -catchfinally自定义异常作为初学者,在刚开始写代码的时候,差不多写一行代码都要见一行红吧异常的体系 这里我们首先需要知道的一点是,所有的异常其实都是类。我们所有的异常都是继承于Throwable这个大类的&#xff…