当前位置: 首页 > news >正文

虚拟dom-Diff算法

虚拟dom-Diff算法

vue2

diff算法在vue2中就是patch,通过新旧虚拟dom对比,找到最小变化然后进行dom操作
在页面首次渲染的时候会调用一次patch并创建新的vnode,不会进行深层次的比较,然后再组件中数据发生变化的时候,会触发setter然后通过notify通知watcher,对应的watcher会通知更新并执行更新函数,会执行render函数获取新的虚拟dom,然后执行patch对比上次渲染结果的老的dom,计算出最小的变化,根据最小的变化去更新真实的dom

什么是diff算法

diff是新旧内容之间的区别经计算,vue中的diff算法,就是通过一种简单而且高效的手段对比出新旧节点数组之间的区别以便以最小的dom操作来更新页面内容

  • 对比的是vnode数组
  • 同时存在新旧两组vnode数组
    真实的dom节点都是树的形式存在的,根节点都是, 为了保证虚拟节点能和真实dom节点一样,vnode也采用树形结构
    如果再组件更新的时候,需要对比全部vnode节点的话,新旧两组节点需要及进行深度遍历和比较,会产生很大的性能开销,所以,vue中默认同层节点比较,多余层级的内容会直接新建或者舍弃,只再同层级进行diff操作
    一般来说,diff操作一般发生在v-for循环或者有v-if/v-else,component这类动态生成的节点对象上

diff算法的优化

只会对比同一层级,不会跨级比较

在这里插入图片描述

比较标签名

如果同一层级的比较标签名不同,旧直接移除老的虚拟节点
在这里插入图片描述

比较key

从标签名相同,key相同,就会被认为是相同节点,也不继续按照这个树状结果做深度比较,比如写v-for的时候会比较key,不写key就会报错
在这里插入图片描述

在不使用key或者列表的index作为key的时候,每个元素对应的位置关系都是index,如果没有key的话,后续的li都会重新渲染。如果使用key的话,后续会判断li3和li4没有发生变化,所以不会重新渲染。

  • key的作用是为了更加搞笑的更新虚拟dom,因为可以非常精确的找到相同节点
  • vue在patch过程中会判断两个节点是不是相同节点,key是一个必要条件。如果在渲染列表的时候,不写key,vue在比较的时候,导致频繁更新元素,使得整个patch比较低效
  • 避免使用数组下标作为key,因为key值不是唯一的话,可能导致出现上图的bug。
  • vue判断两个节点是否相同的时候需要主动判断两者的元素类型和key,如果不设置key,就可能被认为两个相同的节点,只能做更新操作,造成大量不必要的dom更新操作。

双端diff

简单diff算法: 通过暴力手段直接遍历两个数组。双端就是从两端开始分别从中间进行遍历对比的算法

  1. 新旧头相等
  2. 新旧尾相等
  3. 旧头等于新尾
  4. 旧尾等于新头
  5. 四者互不相等
新头旧尾

在这里插入图片描述

头头相等

在这里插入图片描述

尾尾比较

在这里插入图片描述

新尾旧头

在这里插入图片描述

循环比较

在这里插入图片描述

增删

循环没有找到

在这里插入图片描述

头头,尾尾,头尾, 尾头没有匹配到,然后循环遍历,如果循环遍历没有找到,则生成这个节点。

children内增加节点
头头

在这里插入图片描述

尾尾

在这里插入图片描述

children内减少节点

在这里插入图片描述

增加整个children

在这里插入图片描述

删除整个children

在这里插入图片描述

vue3

什么时候用到了diff算法

存在children的vnode类型,element类型中vnode中存在children
flagment碎片类型vnode,可以创建一个具有多个dom节点的组件的方法就是创建一个没有底层vue实例的功能组件

<template><span>1</span><span>2</span><span>3</span>
</template>
// flagment出现就是看起来像一个普通的dom元素,但是是虚拟的,不会在dom树中呈现
<Fragment><span>1</span><span>2</span><span>3</span>
</Fragment>

patchChildren根据是否存在key进行真正的diff或者直接patch

diff算法

头和头比
尾和尾比
基于最长递增子序列进行移动/添加/删除

先进行头和头比较,发现不同旧结束循环
然后进行尾和尾比较,发现不同就结束循环
在保存没有比较过的节点,并通过newIndexToOldIndexMap拿到数组里面对应的下标,生成数组,-1是老数组里没有的就是说明是新增
然后取出数组里面的最长递增子序列,
然后只需要把其他的剩余节点,基于最长子序列的位置进行移动新增和删除就可以了
比较新老children的length获取最小值,然后对于公共部分,重新进行patch工作
如果老节点数量大于新的节点数量,移除多出来的节点
如果新的节点数量大于老的节点数量,重新mountChildren新增的节点
在这里插入图片描述

在这里插入图片描述

如果老节点是否全部patch,新节点没有被patch完,创建新的vnode
如果新节点全部被patch,老节点有剩余,那么卸载所有老节点

最长子序列

这个核心,后续回写

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 通过docker-compose 部署misskey 服务器
  • 开发输出防护栏以检测GPT-4o幻觉
  • 基于springboot3实现单点登录(二):认证服务端搭建
  • 【递归】什么是递归-C语言为例
  • Linux安全与高级应用(九)Linux远程访问与控制:安全与最佳实践
  • 通过python管理mysql
  • 【Qt中2D绘图的类有哪些】
  • 【面试之算法篇】寻找二叉树中两个节点的最低公共祖先
  • JSON 提取器:从文本中提取 JSON 内容的实用工具
  • Android系统Android.bp文件详解
  • el-tree自定义节点内容
  • Java的线程实现
  • 实时捕捉与追溯:得物基于 eBPF 打造云上网络连接异常摄像头
  • Android常用面试题
  • 2024年8月一区SCI-海市蜃楼优化算法Fata morgana algorithm-附Matlab免费代码
  • php的引用
  • angular2 简述
  • Apache Spark Streaming 使用实例
  • export和import的用法总结
  • Markdown 语法简单说明
  • Ruby 2.x 源代码分析:扩展 概述
  • SQLServer插入数据
  • win10下安装mysql5.7
  • 从输入URL到页面加载发生了什么
  • 高性能JavaScript阅读简记(三)
  • 关于extract.autodesk.io的一些说明
  • 力扣(LeetCode)21
  • 前端js -- this指向总结。
  • 试着探索高并发下的系统架构面貌
  • 学习JavaScript数据结构与算法 — 树
  • 一、python与pycharm的安装
  • 移动端 h5开发相关内容总结(三)
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • postgresql行列转换函数
  • 交换综合实验一
  • 扩展资源服务器解决oauth2 性能瓶颈
  • # 利刃出鞘_Tomcat 核心原理解析(七)
  • #define,static,const,三种常量的区别
  • #Java第九次作业--输入输出流和文件操作
  • (03)光刻——半导体电路的绘制
  • (13)[Xamarin.Android] 不同分辨率下的图片使用概论
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (二刷)代码随想录第15天|层序遍历 226.翻转二叉树 101.对称二叉树2
  • (离散数学)逻辑连接词
  • (转)Sublime Text3配置Lua运行环境
  • .libPaths()设置包加载目录
  • .NET Core 中的路径问题
  • .net反编译工具
  • [14]内置对象
  • [20171101]rman to destination.txt
  • [AIGC] MySQL存储引擎详解
  • [AI资讯·0612] AI测试高考物理题,最高准确率100%,OpenAI与苹果合作,将ChatGPT融入系统中,大模型在物理领域应用潜力显现
  • [ASP.NET 控件实作 Day7] 设定工具箱的控件图标
  • [AutoSar]工程中的cpuload陷阱(三)测试