Vue 中 diff 算法原理


一、Diff 概念

Vue 基于虚拟 DOM 做更新。diff 算法的核心就是比较两个虚拟节点的差异,返回一个 patch 对象,这个对象的作用就是存储两个节点不同的地方,最后用 patch 里记录的信息进行更新真实DOM。

diff 算法的在很多场景下都有应用,在Vue中作用于虚拟 DOM 渲染成真实 DOM 的新旧 VNode 节点比较。

1、diff 算法的特点: 

① 比较只会在同层级进行, 不会跨层级比较;

采用的是同级比较的方式。如图,父级和父级比较,儿子和儿子比较,孙子和孙子比较,不考虑跨级比较的情况(因为在实际场景上极少用到,且可以减少比对次数,最大化的提高比对性能,所以不考虑跨级比较的情况)。

② 在 diff 比较的过程中,循环从两边向中间比较;

内部采用深度递归的方式 + 双指针的方式进行比较,不管新旧节点都有首尾两个元素。

 

二、Diff 比较总结

如果两个节点不相同的话,那么直接删除老节点,然后创建新节点。

如果是相同节点,那么会比较两个节点的差异,包括节点的 key 属性、tag 标签、事件等等;

如果两个父节点相同的话,那么就比较儿子节点。

比较子节点有以下4种情况:

  • 如果都是文本节点且不相等,直接将el文本节点更新为新节点的文本内容即可;
  • 如果老的有儿子,新的没儿子,直接删除老的儿子节点;
  • 如果老的没儿子,新的有儿子,那么就创造新的儿子节点,直接插入父节点中;
  • 如果两者都有子节点,则执行 updateChildren 函数比较子节点。

其中,diff 算法的核心是两个都有儿子的情况,这里采用的是双指针和优化比较的策略,优先头头、尾尾、头尾、尾头比较,优化了我们经常使用的 DOM 操作。那若是乱序的情况下,这里的逻辑就是使用节点 key 创建了映射表,然后使用对比查找的方式,根据不同情况执行复用、删除、新增等操作。

在这期间循环向中间靠拢,根据情况调用 patchVnode进行patch重复流程、调用createElem创建一个新节点,从哈希表寻找 key一致的VNode 节点再分情况操作。

三、Diff 比较流程

1、父节点的比较 

① 先比较两个虚拟节点是否是相同节点【key、tag】

主要是比较两个节点的 key 属性和 tag 标签,有任何一个不一样就说明这两个元素不是相同元素

② 如果是相同节点,下一步是比较属性并复用老节点 (将老的虚拟 DOM 复用给新的虚拟节点 DOM)

如果不一样,就会删除老节点,创建新节点 

③ 如果两个父节点相同的话,那么就比较儿子节点,需要以下几种情况:

  • 老的没儿子,新的有儿子。

那么就创造新的儿子节点,直接插入元素中

  • 老的有儿子,新的没儿子。

直接删除老的儿子节点

  • 老的儿子是文本,新的儿子也是文本。

如果不一致,直接更新文本节点即可

  • 老的儿子是一个列表,新的儿子也是一个列表, updateChildren方法

两个列表的比较,也是diff算法的核心所在。一个数组跟另一个数组的比对,有差异就更新。

2、两个列表的比较:优化比较

常见DOM操作:追加、删除、倒序、反序

对应的优化比较策略:头头、尾尾、头尾、尾头

优化方案: 

整个优化采用双指针的方式,也就是在新老节点的头部和尾部分别插入2个指针,在头部和尾部都有一个指针。在比对的过程中,采用的是有一方头尾指针重合的话,就意味着节点遍历结束。这个时候就会终止 diff 算法。

① 头和头节点比较【头头】

首先,比较A和A是否相同,相同则指针向后移动。 B和B,C和C,这时候指针已经越界,diff 算法结束。将 D 直接插入到节点中就可以了。

向尾部插入新节点: 

   

替换尾部不相同的节点:

②  尾和尾节点比较【尾尾】

指针从尾部开始比较新老节点。

向头部插入新节点:

 

替换头部不相同的节点:

③  头和尾节点比较【头尾】

先比较头和头是否相同,再比较尾和尾是否相同。都不相同的时候,那就是用头部比较。 

将老节点的头部跟新节点的尾部比较,相同则将老节点移动到后面去。 

后面就是按照头头比较、尾尾比较、头尾比较这种顺序走。

 

④  尾和头节点比较【尾头】

先比较头和头是否相同,再比较尾和尾是否相同。都不相同的时候,那就是用头尾比较,再不相同就是尾头比较。

将老节点的尾部跟新节点的头部比较,相同则将老节点移动到前面去

头指针比对成功,头指针需要往后移动一格。尾指针比对成功,尾指针需要往前移动一格。

 

⑤ 倒序

 老规矩,递归的使用以下比对策略:先比较头头、尾尾,再比较头尾、尾头

固定一个节点,最后把每个节点进行移动来进行复用。并没有进行重新创建操作

 

3、无法优化比较的情况下,采用对比查找复用的方式:

比对查找进行复用:拿老的节点根据 key 做映射表,然后拿新的节点 key 去映射表中查找。若匹配则比较差异、复用并将其移动到前面去,移走的位置赋值为undefined,不匹配则创建元素并插入。老的节点为空的话,那就自动找下一个节点元素。

乱序的情况下: 通过 key 进行复用,能复用就复用,否则就删除或者创建

先看下是否符合头头、尾尾、头尾、尾头原则。

都不符合的话,那就采用比对查找的方式,那新节点去老节点中查找看是否存在,存在则将节点插到前面去,原来位置置空(位置保留是为了不改变索引位置);不存在则创建,最后把前后指针指向的位置(也就是多余的老节点)删除就行了。

 


四、Vue3 中采用最长递增子序列来实现 diff 优化

例如这个例子中,A和Q不需要移动,直接将E插入中间即可。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机竞赛 地铁大数据客流分析系统 设计与实现

文章目录 1 前言1.1 实现目的 2 数据集2.2 数据集概况2.3 数据字段 3 实现效果3.1 地铁数据整体概况3.2 平均指标3.3 地铁2018年9月开通运营的线路3.4 客流量相关统计3.4.1 线路客流量排行3.4.2 站点客流量排行3.4.3 入站客流排行3.4.4 整体客流随时间变化趋势3.4.5 不同线路客…

6.oracle中listagg函数使用

1. 作用 可以实现行转列,将多列数据聚合为一列,实现数据的压缩 2. 语法 listagg(measure_expr,delimiter) within group ( order by order_by_clause); 解释: measure_expr可以是基于任何列的表达式 delimiter分隔符&#xff0c…

创建harbor仓库并进行一些操作

文章目录 前言一、使用mysql:5.6和 owncloud 镜像,构建一个个人网盘。二、安装搭建私有仓库 Harbor1、安装docker-compse2、安装harbor 3、修改配置文件4、运行脚本5 登入harbor仓库总结 前言 本篇文章需要完成的以下几个操作: 使用mysql:5.6和 ownclo…

爬虫逆向实战(二十)--某99网站登录

一、数据接口分析 主页地址:某99网站 1、抓包 通过抓包可以发现登录接口是AC_userlogin 2、判断是否有加密参数 请求参数是否加密? 通过查看“载荷”可以发现txtPassword和aws是加密参数 请求头是否加密? 无响应是否加密? 无…

【Git版本控制工具使用---讲解一】

Git版本控制工具使用 安装设置用户名签名和邮箱Git常用的命令 初始化本地库查看本地状态Git 命令添加暂存区提交本地库查看版本信息修改文件版本穿梭 安装 首先根据自身电脑的配置选择性的安装是32位的还是64位的Git版本控制工具 我这边安装的是64位的 以下是我安装的时候的过…

C语言:选择+编程(每日一练Day8)

目录 选择题: 题一: 题二: 题三: 题四: 题五: 编程题: 题一:字符个数统计 思路一: 题二:多数元素 思路一: 本人实力有限可能对一些…

事件捕获和事件冒泡

事件捕获和事件冒泡与事件流有关系。 以下代码&#xff0c;点击 aa &#xff0c;控制台会打印什么呢&#xff1f; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content&q…

Docker(一)-安装、架构、业务开发常用命令、Dockerile、镜像卷、镜像仓库

基于业务开发使用Docker Docker是一个开源的容器引擎&#xff0c;它有助于更快地交付应用。Docker可将应用程序和基础设施层隔离&#xff0c;并且能将基础设施当作程序一样进行管理。使用 Docker可更快地打包、测试以及部署应用程序&#xff0c;并可以缩短从编写到部署运行代码…

App Inventor 2 开发 ChatGPT 对话App

ChatGPT大家应该不会陌生&#xff0c;它的回答内容非常的专业及深入&#xff0c;具有实际的可指导性。我们通过App Inventor 2开发一个简单的对话App&#xff0c;先看效果&#xff1a; App Inventor 2 ChatGPT教育领域对话演示 代码块如下&#xff1a; 用到的核心组件“ChatBot…

kafka--技术文档--spring-boot集成基础简单使用

阿丹&#xff1a; 查阅了很多资料了解到&#xff0c;使用了spring-boot中整合的kafka的使用是被封装好的。也就是说这些使用其实和在linux中的使用kafka代码的使用其实没有太大关系。但是逻辑是一样的。这点要注意&#xff01; 使用spring-boot整合kafka 1、导入依赖 核心配…

Web3和去中心化:互联网的下一个演化阶段

文章目录 Web3和去中心化的定义Web3&#xff1a;去中心化&#xff1a; 为什么Web3和去中心化如此重要&#xff1f;数据隐私和安全&#xff1a;去中心化的创新&#xff1a;去除中间商&#xff1a; Web3和去中心化的应用领域去中心化金融&#xff08;DeFi&#xff09;&#xff1a…

掌握AI助手的魔法工具:解密Prompt(提示)在AIGC时代的应用「上篇」

在当今的AIGC时代&#xff0c;我们面临着越来越多的人工智能技术和应用。其中一个引人注目的工具就是Prompt&#xff08;提示&#xff09;。它就像是一种魔法&#xff0c;可以让我们与AI助手进行更加互动和有针对性的对话。那么&#xff0c;让我们一起来了解一下Prompt&#xf…

长胜证券:货币政策什么意思?

钱银政策是指国家钱银当局经过调控钱银供给量和利率等手法&#xff0c;以到达操控通货膨胀、坚持经济稳定、促进经济增长等目的的一种宏观经济政策。简而言之&#xff0c;钱银政策便是国家中央银行对钱银供给和利率进行调控的政策。那么具体来说&#xff0c;钱银政策到底有哪些…

windwos系统如何创建typecho个人博客并通过内网穿透实现无公网IP访问

文章目录 前言1. 环境安装2.安装Typecho3.安装cpolar内网穿透4. 固定公网地址5.配置Typecho 前言 Typecho是一款PHP语言编写的开源博客程序&#xff0c;它是一个轻量级的内容管理系统&#xff0c;专注于博客领域。支持多用户、多站点、多语言等功能&#xff0c;可以满足不同用…

水库大坝安全监测的主要内容包括哪些?

在水库大坝的实时监测中&#xff0c;主要任务是通过无线传感网络监测各个监测点的水位、水压、渗流、流量、扬压力等数据&#xff0c;并在计算机上用数据模式或图形模式进行实时反映&#xff0c;以掌握整个水库大坝的各项变化情况。大坝安全监测系统能实现全天候远程自动监测&a…

CSS中的vertical-align属性

vertical-align 1.CSS属性 - vertical-align 2.深入理解vertical-align – line boxes This property affects the vertical positioning inside a line box of the boxes generated by an inline-levelelement. 官方文档的翻译&#xff1a;vertical-align会影响 行内块级元素…

Python“牵手”速卖通商品列表数据,关键词搜索速卖通API接口数据,速卖通API接口申请指南

速卖通平台API接口是为开发电商类应用程序而设计的一套完整的、跨浏览器、跨平台的接口规范&#xff0c;速卖通API接口是指通过编程的方式&#xff0c;让开发者能够通过HTTP协议直接访问速卖通平台的数据&#xff0c;包括商品信息、店铺信息、物流信息等&#xff0c;从而实现速…

Unity 之transform.LookAt() 调整一个物体的旋转,使其朝向指定的位置

文章目录 总的介绍补充&#xff08;用于摄像机跟随的场景&#xff09; 总的介绍 transform.LookAt 是 Unity 引擎中 Transform 组件的一个方法&#xff0c;用于调整一个物体的旋转&#xff0c;使其朝向指定的位置。通常情况下&#xff0c;它被用来使一个物体&#xff08;如摄像…

HarmonyOS开发:超详细了解项目的工程结构

前言 系列文章目录&#xff1a; HarmonyOS开发第一步&#xff0c;熟知开发工具DevEco Studio 当我们熟练的掌握了DevEco Studio之后&#xff0c;就可以创建项目进行练习了&#xff0c;和市场上大多数IDE一样&#xff0c;DevEco Studio也给我们提供了很多的实例模板&#xff0c…

如何远程管理服务器详解

文章目录 前言一、远程管理类型二、远程桌面三、telnet 命令行远程四、查看本地开放端口 前言 很多公司是有自己的机房的&#xff0c;机房里面会有若干个服务器为员工和用户提供服务。大家可以想想&#xff1a;假设这家公司有上百台服务器&#xff0c;我们作为网络工程师&…