vue-vue2和vue3的diff算法
核心要点
- 数据变化时,vue如何更新节点
- 虚拟DOM 和 真实DOM 的区别
- vue2 diff 算法
- vue3 diff 算法
一、 数据变化时,vue如何更新节点
首先渲染真实DOM的开销是很大,比如有时候我们修改了某个数据且修改的数据量很大时,此时会频繁的操作真实dom,会不断的引起整个dom树的重绘和重排;vue是根据真实DOM生成一颗 虚拟DOM,当 虚拟DOM 某个节点的数据改变后会生成一个新的newVnode,然后newVnode和oldVnode作对比,发现有不一样的地方就直接修改在真实的DOM上
二、虚拟DOM 和 真实DOM 的区别
虚拟DOM是将真实的DOM的数据抽取出来,以对象的形式模拟树形结构;
//真实DOM
<div><p>123</p>
</div>//虚拟DOM
var Vnode = {tag: 'div',children: [{ tag: 'p', text: '123' }]
};
三、vue2 diff 算法
核心原理
- 深度优先,同层比较,时间复杂度只有 O(n);
- 双针比较,新头与旧头比较,新尾与旧尾比较,旧头与新尾比较,新头与旧尾比较
diff算法流程
(1)diff算法是发生在更新的过程,而更新的情况有以下几种情况
- 老的是Text,新的是Text,直接更新
- 老的是Array,新的是Text,把旧的全部删掉,更新为Text
- 老的是Text,新的是Array,删掉旧的文本,更新为新的Array元素
- 老的是Array,新的是Array,调用updateChildren函数比较子节点,这是diff的核心
(2)老的是Array,新的是Array的情况下,调用updateChildren函数,diff核心流程
- 新旧节点VNode节点如下图所示

- 循环遍历节点
① 情况:当新老 VNode 节点的 start 满足 sameVnode 时,直接 patchVnode 即可,同时新老 VNode 节点的开始索引都加 1
② 情况:当新老 VNode 节点的 end 满足 sameVnode 时,同样直接 patchVnode 即可,同时新老 VNode 节点的结束索引都减 1if (sameVnode(oldStartVnode, newStartVnode)) {patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)oldStartVnode = oldCh[++oldStartIdx]newStartVnode = newCh[++newStartIdx] }
③ 情况:当老 VNode 节点的 start 和新 VNode 节点的 end 满足 sameVnode 时,这说明这次数据更新后 oldStartVnode 已经跑到了 oldEndVnode 后面去了。这时候在 patchVnode 后,还需要将当前真实 dom 节点移动到 oldEndVnode 的后面,同时老 VNode 节点开始索引加 1,新 VNode 节点的结束索引减 1else if (sameVnode(oldEndVnode, newEndVnode)) {patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)oldEndVnode = oldCh[--oldEndIdx]newEndVnode = newCh[--newEndIdx] }
④ 情况:当老 VNode 节点的 end 和新 VNode 节点的 start 满足 sameVnode 时,这说明这次数据更新后 oldEndVnode 跑到了 oldStartVnode 的前面去了。这时候在 patchVnode 后,还需要将当前真实 dom 节点移动到 oldStartVnode 的前面,同时老 VNode 节点结束索引减 1,新 VNode 节点的开始索引加 1。else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved rightpatchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))oldStartVnode = oldCh[++oldStartIdx]newEndVnode = newCh[--newEndIdx] }
⑤ 以上都不满足的情况:如果新旧子节点都存在key,那么会根据oldVnode的key生成一张hash表,用当前新节点,暂时称为S的key与hash表做匹配,匹配成功就判断S和匹配节点是否为sameNode,如果是,就在真实dom中将成功的节点移到最前面,否则,将S生成对应的节点插入到dom中对应的oldS位置,S指针向中间移动,被匹配old中的节点置为undefined。如果没有key,则直接将S生成新的节点插入真实DOM(ps:这下可以解释为什么v-for的时候需要设置key了,如果没有key那么就只会做四种匹配,就算指针中间有可复用的节点都不能被复用了)else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved leftpatchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);oldEndVnode = oldCh[--oldEndIdx];newStartVnode = newCh[++newStartIdx]; }
四、vue3 diff 算法
核心原理
- 深度优先,同层比较,时间复杂度只有 O(n);
- 双端对比算法:先看左侧,看完左侧看右侧,然后锁定中间乱序的部分
- 最长递增子序列:针对中间乱序部分,采用最长递增子序列的算法,计算出乱序部分可以复用的最长连续节点
diff算法流程
(1)diff算法是发生在更新的过程,而更新的情况有以下几种情况
- 老的是Text,新的是Text,直接更新
- 老的是Array,新的是Text,把旧的全部删掉,更新为Text
- 老的是Text,新的是Array,删掉旧的文本,更新为新的Array元素
- 老的是Array,新的是Array,调用updateChildren函数比较子节点,这是diff的核心
(2)老的是Array,新的是Array的情况下,调用updateChildren函数,diff核心流程
-
先处理左侧,先从左侧开始进行对比,很明显左侧的A、B都是相同的,然后锁定左侧相同的部分,处理右侧乱序部分

-
再处理右侧,从右侧开始对比,很明显右侧的B、C都是相同的,然后锁定右侧相同部分,处理左侧乱序部分

-
若新的比老的长,创建,可以看到下图新的比老的多,新的多了一个D,多出来的这个节点就需要创建并添加到尾部

-
老的比新的长,删除,可以看到下图老的比新的多了个C,多出来的这个节点需要删除

-
乱序部分,采用最长递增子序列的算法,最大递增子序列的作用就是通过新旧节点变化前后的映射,创建一个递增数组,这样就可以知道哪些节点在变化前后相对位置没有发生变化,哪些节点需要进行移动,如下图计算出E、F、Y、J 是不需要操作的节点,直接复用,然后移动K节点,即可完成一次更新;关于最长递增子序列的算法参考视频,算法核心:动态规划+二分法实现+驱节点向前(回溯) 的方式,实现了O(n logn)的时间复杂度查找

参考文章
- Vue2、Vue3的diff对比
- 根据大崔哥的mini-vue来理解vue3中的diff算法
- 手写Vue3框架教程(核心原理、组件渲染、diff算法、生命周期…)
相关文章:
vue-vue2和vue3的diff算法
核心要点 数据变化时,vue如何更新节点虚拟DOM 和 真实DOM 的区别vue2 diff 算法vue3 diff 算法 一、 数据变化时,vue如何更新节点 首先渲染真实DOM的开销是很大,比如有时候我们修改了某个数据且修改的数据量很大时,此时会频繁的…...
一文解读基于PaddleSeg的钢筋长度超限监控方案
项目背景 钢铁厂生产钢筋的过程中会存在部分钢筋长度超限的问题,如果不进行处理,容易造成机械臂损伤。因此,需要通过质检流程,筛选出存在长度超限问题的钢筋批次,并进行预警。传统的处理方式是人工核查,该方…...
NumPy 数组学习手册:1~5
原文:Learning NumPy Array 协议:CC BY-NC-SA 4.0 译者:飞龙 一、NumPy 入门 让我们开始吧。 我们将在不同的操作系统上安装 NumPy 和相关软件,并查看一些使用 NumPy 的简单代码。 正如“序言”所述,SciPy 与 NumPy 密…...
【C++11】晦涩难懂语法系列:可变参数模板
目录 可变参数模板 1.1 概念 1.2 可变参数模板定义 1.3 参数包的展开方式 1.3.1 递归展开参数包 1.3.2 逗号表达式展开参数包 1.4 STL的emplace系列函数 可变参数模板 1.1 概念 在C语言阶段,我们已经接触过可变参数,比如scand、printf等等 这里…...
计算机组成原理第二章——数据的表示与运算(下)
提示:时光清浅处 一步一安然 文章目录 前言2.3.1 浮点数的表示2.3.2 IEEE7542.2.3 浮点数的运算 前言 本节主要讲三个问题,浮点数的表示,IEEE 754标准,浮点数的加减运算 2.3.1 浮点数的表示 浮点数的作用和基本原理 定点数可表…...
1.mybatis-plus入门及使用
1.什么是MybatisPlus MyBatis-Plus 官网 为什么要学MybatisPlus? MybatisPlus可以节省大量时间,所有的CRUD代码都可以自动化完成MyBatis-Plus是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效…...
JavaWeb开发 —— 前端工程化
目录 一、前后端分离开发 二、YApi 三、前端工程化 1. 环境准备:vue-cli 2. Vue项目创建 四、Vue项目开发流程 一、前后端分离开发 ① 最早的前端开发就是实现页面,顶多再写写JS让页面可以有交互的特效。属于前后端未分离的时代。 早期前后端混合开…...
listener监听器框架
监听器是Web开发中常用的一种组件,用于监听某些事件并根据事件触发相应的处理逻辑。在Spring Boot中使用监听器可以方便地实现对程序中各种事件的监听,比如启动事件、关闭事件等。 首先需要定义一个监听器,通常需要实现ApplicationListener接…...
tp5实现导入excel表到数据库
hello,大家好,好长时间没有更新文章了。最近一直在忙着做项目。所以断更了。 那么好,各位老铁是否想要实现导入导出的功能 请关注我,解密如何实现导入导出, 那么今天先来讲一下用thinkphp5.0 如何实现Excel表格导入数据…...
Python基础-04 字符串
字符串的表示方式 在Python中,可以使用一对单引号/双引号或者一对三个双引号/一对三个单引号表示字符串 a hello b "hello" c hello d """hello""" # 如果字符串里面还有双引号,外面就可以使用单引号 # 反之一样 # 如果字符串里…...
VVC之编码结构
VVC之编码结构(新一代通用视频编码的读书笔记) 缩写概述EncAppmain函数解读 缩写 缩写含义CVSCoded Video Sequence, 编码视频序列IRAPIntra Random Access Point, 帧内随机接入点GDRGradual Decoding Refresh, 逐渐解码刷新AUAccess Unit, 访问单元PUP…...
FPGA基于SFP光口实现10G万兆网UDP通信 10G Ethernet Subsystem替代网络PHY芯片 提供工程源码和技术支持
目录 1、前言2、我这里已有的UDP方案3、详细设计方案4、vivado工程详解5、上板调试验证并演示6、福利:工程代码的获取 1、前言 目前网上的fpga实现udp基本生态如下: 1:verilog编写的udp收发器,但不带ping功能,这样的代…...
Linux Redis主从复制 | 哨兵监控模式 | 集群搭建 | 超详细
Linux Redis主从复制 | 哨兵监控模式 | 集群搭建 | 超详细 一 Redis的主从复制二 主从复制的作用三 主从复制的流程四 主从复制实验4.1 环境部署4.2 安装Redis(主从服务器)4.3 修改Master节点Redis配置文件 (192.168.163.100)4.4 修改Slave节点Redis配置…...
整柜海运到美国的规格和收费标准是什么
整柜海运是指将所有货物安装在一个整箱内,由发货人和收货人共同操作,而目的港的收货人一般只有一个,方便操作。整柜海运到美国的主要流程有以下几个步骤:订舱、装柜、报关、海运、清关、提柜和送货。实际上,国际物流出…...
Session和Cookie区别介绍+面试题
Session 会话: 对应的英文单词:session用户打开浏览器,进行一系列操作,然后关闭浏览器。整个过程叫做一次会话一个会话包含多次请求 session机制属于B/S结构的一部分,主要的作用就是为了保存会话状态。(用户登录成功后…...
easyx
普通的画线图什么的 首先我们需要安装一个easyx的图形库,然后把头文件搞出来 #include <stdio.h> #include <easyx.h>//easyx画线啥啥的图形库 #include <graphics.h> #include <math.h> #include <conio.h>//键盘操作的头文件 设…...
记一次科学
华为云与Centos8 华为云99元Hongkong的服务器:1M,1C,2G,40G,自带不可更改的Centos 8.2 64bit 华为yum源不可以,网上找了可用的CentOS8 官方源不支持后配置yum源 # 备份 mv /etc/yum.repos.d/CentOS-Base…...
亚马逊被人差评了怎么办?
第一种: 也是最简单的做法就是通过电话或者邮件联系留差评的买家,大致意思就是按照货值的2-3倍作为赔偿,能不能把差评给删了 赔偿一个普通产品2-3倍的价格比起找服务商删一个差评几百到一千不等可以说是绰绰有余了,碰到那种愿意…...
【目标检测】YOLOv5:修改自己的网络结构
前言 YOLOv5就像一座金矿,里面有无数可以学习的东西。之前的博文一直将YOLOv5当作一个黑盒使用,只考虑模型的输入和输出,以此来对模型进行二次开发。 本篇博文将更近一层,深入到“金矿”内部,来尝试对模型结构进行替换…...
spring boot 工程整合mongodb,遇到的坑
首先说一下背景,因为其他的一个web工程有使用mongo,我想着给另外一个工程把mongo也加过来吧。也是最近做一个发送 丘比特信 的需求,觉得这个信应该是存到 mongodb。结果拿过来遇到了很大的坑,也是对版本对原理不了解吧。 下面介…...
Graph-CoT:图神经网络结合思维链,实现复杂图结构推理
1. 项目概述:当图神经网络遇上思维链推理最近在复现和优化一些图相关的推理任务时,我反复遇到了一个瓶颈:传统的图神经网络模型在处理需要多步逻辑推理的问题时,比如社交网络中的影响力传播预测、知识图谱上的复杂问答,…...
Hermes 的核心架构 Harness:上下文、工具、权限与执行控制
上一篇写 Hermes-Agent,我们选了一条比较笨但好用的路:跟一条消息走一遍。 从终端里敲下一句话,到 Agent 把最后一个字回到屏幕上,中间其实绕了很长一圈: 消息先被入口收进去,变成内部统一的消息…...
终极窗口置顶解决方案:用AlwaysOnTop告别多任务切换烦恼
终极窗口置顶解决方案:用AlwaysOnTop告别多任务切换烦恼 【免费下载链接】AlwaysOnTop Make a Windows application always run on top 项目地址: https://gitcode.com/gh_mirrors/al/AlwaysOnTop 你是否经常需要在不同窗口间来回切换?是否觉得频…...
长期使用Taotoken Token Plan套餐的成本控制体会
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 长期使用Taotoken Token Plan套餐的成本控制体会 1. 从按需计费到套餐订阅的转变 在开始使用Taotoken平台时,我和团队…...
基于Ollama与Streamlit的本地大模型智能对话应用snowChat部署指南
1. 项目概述:一个基于本地大模型的智能对话应用最近在折腾本地部署的大语言模型,发现了一个挺有意思的项目,叫snowChat。这名字听起来就挺“冷”的,但功能却很“热”——它本质上是一个让你能在自己电脑上,用本地的大模…...
LSPatch:无需Root的Android应用模块化终极指南
LSPatch:无需Root的Android应用模块化终极指南 【免费下载链接】LSPatch LSPatch: A non-root Xposed framework extending from LSPosed 项目地址: https://gitcode.com/gh_mirrors/ls/LSPatch 你是否曾经羡慕iOS的越狱插件,却因Android设备未ro…...
Arm Neoverse V2内存架构与PCIe地址管理解析
1. Arm Neoverse V2内存架构设计精要 在Arm Neoverse V2的体系结构中,内存映射机制是其高性能计算能力的基石。这套架构通过精细的地址空间划分,实现了对各类硬件资源的高效管理。我们先来看一个典型的多芯片系统内存布局示例: Chip 0: 0x0…...
OpenUPM安全最佳实践:保护你的Unity包注册表完全指南 [特殊字符]
OpenUPM安全最佳实践:保护你的Unity包注册表完全指南 🔒 【免费下载链接】openupm OpenUPM - Open Source Unity Package Registry (UPM) 项目地址: https://gitcode.com/gh_mirrors/op/openupm OpenUPM作为开源Unity包管理器(UPM&…...
Python对象状态持久化:Memoripy库实现增量更新与断点续跑
1. 项目概述:一个让Python程序拥有“记忆”的魔法库如果你写过一些需要处理大量数据或者进行复杂状态管理的Python脚本,肯定遇到过这样的场景:程序运行到一半,因为网络波动、数据异常或者你手动中断,不得不从头再来。那…...
IDEA项目乱码终结指南:从UTF-8全局设置到.properties文件特殊处理
IDEA项目乱码终结指南:从UTF-8全局设置到.properties文件特殊处理 在Java开发中,编码问题就像一颗定时炸弹,随时可能在最意想不到的时刻引爆。特别是当项目涉及多语言支持、团队协作或接手遗留代码时,乱码问题往往成为开发者挥之不…...
