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

前端开发:关于diff算法详解

前言

前端开发中,关于JS原生的内容和前端算法相关的内容一直都是前端工作中的核心,不管是在实际的前端业务开发还是前端求职面试,都是非常重要且必备的内容。那么本篇博文来分享一个关于前端开发中必备内容:diff算法,diff算法在前端实战中和前端求职面试中都是必备知识,整理总结一下,方便查阅使用。

diff算法是什么?

diff算法其实就是用于比较新旧虚拟DOM节点的差异性的算法。众所周知,每一个虚拟DOM节点都会有一个唯一标识,即Key,diff算法把树形结构按照层级分解,只比较同级元素,不同层级的节点只有创建和删除操作,通过对比新旧节点的Key来判断当前节点是否改变,把两个节点不同的地方存储在patch对象中,然后利用patch记录的消息进行局部更新DOM操作。

注意:若输入的新节点不是虚拟DOM , 那么需要将DOM节点转换为虚拟DOM才行,也就是说diff算法是针对虚拟DOM的。

patch()函数

patch函数其实就是用于节点上树,更新DOM的函数,也就是将新旧节点进行比较的函数。

diff算法的诞生

想必大家都知道,前端领域中在之前传统的DOM操作非常昂贵,数据的改变往往需要更新 DOM 树上的多个节点,可谓是牵一发而动全身,所以虚拟DOM和Diff算法的诞生就是为了解决上述问题。

前端的Web界面由 DOM 树来构成,当某一部分发生变化的时候,其实就是对应的某个 DOM 节点发生了变化。在 Vue中,构建 UI 界面的思路是由当前状态决定界面,前后两个状态就对应两套界面,然后由 Vue来比较两个界面的区别,本质是比较 DOM 节点差异当两个节点不同时应该如何处理,分为两种情况:一、节点类型不同;二、节点类型相同,但是属性不同。了解它们就需要对 DOM 树进行 Diff 算法分析。

diff算法的优势

diff算法的性能优势在于对比新旧两个 DOM节点的不同的时候,只对比同一级别的 DOM 节点,一旦发现有不同的地方,后续的DOM子节点将被删掉而不再作对比操作。使用diff算法提高了更新DOM的性能,不用再把整个页面全部删除后重新渲染;使用diff算法让虚拟DOM只包括必须的属性,不再把真实DOM的全部属性都拿出来。

diff算法的示例

这里先来以Vue来介绍一下diff算法的示例,这里直接在vue文件的模板中进行一个简单的标签实现,需要被vue处理成虚拟DOM,然后渲染到真实DOM中,具体代码如下所示:

//标签设置

<template>
<div id="content">
<p class="sonP">Hello</p>
</div>
</template>

//相对应的虚拟DOM结构

const dom = {type: 'div',attributes: [{id: 'content'}],children: {type: 'p',attributes: [{class: 'sonP'}],text: 'Hello'}}

通过上面的代码演示可以看到,新建标签之后,系统内存中会生成对应的虚拟DOM结构,由于真实DOM属性有很多,无法快速定位是哪个属性发生改变,然后通过diff算法能够快速找到发生变化的地方,然后只更新发生变化的部分渲染到页面上,也叫打补丁。

虚拟DOM

虚拟DOM是保存在程序内存中的,它只记录DOM的关键信息,然后结合diff算法来提高DOM更新的性能操作,在程序内存中比较差异,最后给真实DOM打补丁更新操作。

diff算法的比较规则

diff算法在进行比较操作的规则是这样的:

  1. 新节点前和旧节点前;
  2. 新节点后和旧节点后;
  3. 新节点后和旧节点前;
  4. 新节点前和旧节点后。

只要符合一种情况就不会再进行判断,若没有符合的,就需要循环来寻找,移动到旧前之前操作。结束查找的前提是:旧节点前新节点前。

 

diff算法的三种比较方式

diff算法的比较方式有三种,分别如下所示:

方式一:根元素发生改变,直接删除重建

也就是同级比较,根元素发生改变,整个DOM树会被删除重建。如下示例:

//旧的虚拟DOM

<ul id="content">
<li class="sonP">hello</li>
</ul>

//新的虚拟DOM

<div id="content">
<p class="sonP">hello</p>
</div>

方式二:根元素不变,属性改变,元素复用,更新属性

这种方式就是在同级比较的时候,根元素不变,但是属性改变之后更新属性,示例如下所示:

//旧的虚拟DOM

<div id="content">
<p class="sonP">hello</p>
</div>

//新的虚拟DOM

<div id="content" title="hello">
<p class="sonP">hello</p>
</div>

方式三:根元素不变,子元素不变,元素内容发生变化

也就是根元素和子元素都不变,只是内容发生改变,这里涉及到三种小的情况:无Key直接更新、有Key但以索引为值、有Key但以id为值。

1、无Key直接更新

无Key直接就地更新,由于v-for不会移动DOM,所以只是尝试复用,然后就地更新;若需要v-for来移动DOM,则需要用特殊 attribute key 来提供一个排序提示。示例如下所示:

<ul id="content">
<li v-for="item in array">
{{ item }}
<input type="text">
</li>
</ul>
<button @click="addClick">在下标为1的位置新增一行</button>
export default {
data(){
return {
array: ["11", "44", "22", "33"]
}
},
methods: {
addClick(){
this.array.splice(1, 0, '44')
}
}
};

2、有Key但以索引为值

这里也是直接就地更新,通过新旧虚拟DOM对比,key存在就直接复用该标签更新的内容,若key不存在就直接新建一个。示例如下所示:

<ul id="content">
<li v-for="(item, index) in array" :key="index">
{{ item }}
<input type="text">
</li>
</ul>
<button @click="addClick">在下标为1的位置新增一行</button>
export default {
data(){
return {
array: ["11", "44", "22", "33"]
}
},
methods: {
addClick(){
this.array.splice(1, 0, '44')
}
}
};

通过上面代码可以看到,通过v-for循环产生新的DOM结构, 其中key是连续的, 与数据对应一致,然后比较新旧DOM结构, 通过diff算法找到差异区别, 接着打补丁到页面上,最后新增补一个li,然后从第二元素以后都要更新内容。

3、有Key但以id为值

由于Key的值只能是唯一不重复的,所以只能以字符串或数值来作为key。由于v-for不会移动DOM,所以只是尝试复用,然后就地更新;若需要v-for来移动DOM,则需要用特殊 attribute key 来提供一个排序提示。

若新DOM数据的key存在, 然后去旧的虚拟DOM里找到对应的key标记的标签, 最后复用标签;若新DOM数据的key存在, 然后去旧的虚拟DOM里没有找到对应的key标签的标签,最后直接新建标签;若旧DOM结构的key, 在新的DOM结构里不存在了, 则直接移除对应的key所在的标签。

<ul id="content">
<li v-for="object in array" :key="object.id">
{{ object.name }}
<input type="text">
</li>
</ul>
<button @click="addClick">在下标为1的位置新增一行</button>
export default {
data(){
return {
array: [{id:11,name:"11"}, {id:22,name:"22"}, {id:33,name:"33"}]
}
},
methods: {
addClick(){
this.array.splice(1, 0,{id:44,name: '44'})
}
}
};

最后

通过本文关于前端开发中关于diff算法的详细介绍,diff算法不管是在实际的前端开发工作中还是在前端求职面试中都是非常关键的知识点,所以作为前端开发者来说必须要掌握它相关的内容,尤其是从事前端开发不久的开发者来说尤为重要,是一篇值得阅读的文章,重要性就不在赘述。欢迎关注,一起交流,共同进步。

相关文章:

前端开发:关于diff算法详解

前言 前端开发中&#xff0c;关于JS原生的内容和前端算法相关的内容一直都是前端工作中的核心&#xff0c;不管是在实际的前端业务开发还是前端求职面试&#xff0c;都是非常重要且必备的内容。那么本篇博文来分享一个关于前端开发中必备内容&#xff1a;diff算法&#xff0c;d…...

如何为报表开发工具 FastReport .NET 设置 Apache 2 Web 服务器?

FastReport .NET是一款全功能的Windows Forms、ASP.NET和MVC报表分析解决方案&#xff0c;使用FastReport .NET可以创建独立于应用程序的.NET报表&#xff0c;同时FastReport .Net支持中文、英语等14种语言&#xff0c;可以让你的产品保证真正的国际性。专业版和企业版包括Fast…...

华为OD机试真题JAVA实现【出租车计费】真题+解题思路+代码(20222023)

🔥系列专栏 华为OD机试(JAVA)真题目录汇总华为OD机试(Python)真题目录汇总华为OD机试(C++)真题目录汇总华为OD机试(JavaScript)真题目录汇总文章目录 🔥系列专栏题目输入输出示例一输入输出说明示例二输入输出说明...

MySQL 查看版本的 5 种方法

MySQL 提供了几种用于查看服务器版本的方法&#xff0c;本文给大家做个简单的介绍。 方法一&#xff1a;登录 MySQL 每次通过 mysql 客户端连接服务器之后&#xff0c;都会显示一个欢迎信息&#xff0c;里面包含了服务器的版本&#xff1a; mysql -uroot Enter password: **…...

【软件测试】稳定性测试怎么做,这篇文章彻底讲透了~

稳定性对产品的重要性不言而喻。 而作为质量保障&#xff0c;在稳定性测试方面的探索也在不断演化。记得两年前我们做稳定性测试还是基于恒定的压力&#xff0c;7*24小时长时间运行&#xff0c;关注的指标无非是吞吐量TPS的抖动、响应时间的变化趋势&#xff0c;以及各种资源是…...

Leetcode:198. 打家劫舍、213. 打家劫舍 II、337. 打家劫舍 III(C++)

目录 198. 打家劫舍 问题描述&#xff1a; 实现代码与解析&#xff1a; 动态规划&#xff08;版本一&#xff09;&#xff1a; 原理思路&#xff1a; 动态规划&#xff08;版本二&#xff09;&#xff1a; 原理思路&#xff1a; 213. 打家劫舍 II 问题描述&#xff1a…...

【每日随笔】手指训练 ( 手指训练作用 | 哪些人需要手指训练 | 手指操 | 手指康复训练器材 )

文章目录一、手指训练作用二、哪些人需要手指训练三、手指操四、手指康复训练器材产品需求探索 , 研究下手指训练的市场 , 前景 , 是否可以开发 ; 一、手指训练作用 手指训练作用 : 改善 上肢协调性手眼 协调性训练提高 手指 抓握 能力提高 手指 灵活性提高 上肢运动 准确性 和…...

ATR指标在外汇交易中的另类运用方法

当涉及到外汇交易时&#xff0c;有许多不同的指标可以使用。然而&#xff0c;ATR指标可能是一个被低估的工具&#xff0c;可以帮助您发现有利可图的交易机会。本文将介绍ATR指标是什么&#xff0c;如何使用它来识别价格波动和制定交易策略&#xff0c;以及如何在外汇市场中另辟…...

SQL Server 数据批量导出处理

在实际项目环境中&#xff0c;有时会遇到需要将大量数据&#xff08;这里所指百万级别以上的数据量&#xff09;从一台服务器迁移到另外一台数据库服务器的情况。SQL Server有很多方式可以进行数据迁移&#xff1a;备份还原、导入/导出数据、生成脚本&#xff08;包含数据&…...

虹科分享 | CANopen协议基础知识——LSS服务

CANopen是一种架构在CAN串行总线系统上的高层通讯协议&#xff0c;常被用于嵌入式系统与工业控制领域&#xff0c;包括电机控制、机器人制造、医疗、汽车等多个行业领域。本篇文章将主要介绍CANopen的LSS服务。 一. LSS概述 Layer setting service (LSS)是CANopen的设置服务与…...

JS混淆和解混淆

在今天的数字时代&#xff0c;知识产权和商业机密对于企业的成功非常重要。JavaScript代码可以包含许多敏感信息&#xff0c;例如商业逻辑、客户数据和加密密钥。为了保护这些重要信息&#xff0c;JavaScript混淆和解混淆已经成为一种必要的技术。 什么是JavaScript混淆&#…...

MySQL-数值函数

绝对值函数语法格式&#xff1a;ABS(X)例&#xff1a;查看三个数值的绝对值&#xff08;负的绝对值为它的正整数&#xff0c;0的绝对值为0&#xff0c;正的绝对值为它本身&#xff09;。mysql> select abs(2),abs(-32),abs(-0.5); ----------------------------- | abs(2) |…...

SpringMVC(1)

Web项目:基于HTTP协议&#xff0c;当一个用户从浏览器上面输入URL地址之后&#xff0c;URL能够和我们的程序映射起来&#xff0c;可以让用户的请求触达到后端程序里面&#xff0c;并且根据程序的处理&#xff0c;把结果返回浏览器&#xff1b; Spring MVC要进行学习的内容: 1)连…...

珠海先达MES系统六大功能解决电子组装行业可视化问题

电子组装行业的发展背景&#xff1a; 在日益激烈的市场环境中&#xff0c;降低成本&#xff0c;加快交付周期&#xff0c;提高产品质量已经成为了制造业发展的重要目标。企业关注的是产品的生产周期&#xff0c;客户关注的是产品的质量。如何在企业和消费者达成平衡&#xff0c…...

获取本机的IP地址,看似简单的获取,实则蕴含非常多的操作

这篇文章讲述了PowerJob获取本地IP离奇曲折的经过&#xff0c;以及开放了诸多的可配置参数&#xff0c;打开了我新世界的大窗户。求个关注&#xff0c;求个点赞&#xff0c;求一个评论。 获取地址的操作&#xff0c;本来不应该作为什么重点&#xff0c;但是因为一点小小的意外&…...

【SSM】篇一:初试Spring--Ioc与Bean

文章目录1、Spring2、SpringFramework系统架构3、BeanBean的配置Bean的实例化Bean的生命周期4、依赖注入DIsetter注入和构造器注入依赖自动装配5、集合注入1、Spring Spring地址&#xff1a;https://spring.io Spring技术的优点&#xff1a; Spring家族&#xff08;Spring全家…...

华为OD机试真题Python实现【出租车计费】真题+解题思路+代码(20222023)

🔥系列专栏 华为OD机试(Python)真题目录汇总华为OD机试(JAVA)真题目录汇总华为OD机试(C++)真题目录汇总华为OD机试(JavaScript)真题目录汇总文章目录 🔥系列专栏题目输入输出示例一输入输出说明示例二输入输出说明...

Elasticsearch:如何修改 nested 字段的值

Nested 类型是 object 数据类型的特殊版本&#xff0c;它允许对象数组以一种可以彼此独立查询的方式进行索引。在内部&#xff0c;嵌套对象将数组中的每个对象索引为单独的隐藏文档&#xff0c;这意味着每个嵌套对象都可以使用 nested query 独立于其他对象进行查询。每个 nest…...

【JAVA】jdk8 Stream 排序精通

背景 jdk8的stream流能方便的排序&#xff0c;但是每次都要查资料&#xff0c;非常不方便&#xff0c;不确定&#xff0c;所以这次直接弄懂&#xff0c;不再迷茫。 转载请注明来源&#xff0c;创作不易&#xff0c;请多多支持。 基础排序 stream流 大家应该都比较熟悉了&…...

python的opencv操作记录12——Canny算子使用

文章目录Canny算子非极大值抑制非极大值抑制中的插值滞后阈值实际应用直接使用Canny算子使用膨胀先阈值分割Canny算子 上一篇说到&#xff0c;我在一个小项目里需要在一幅图像中提取一根试管里的两种液体的截面。为了达到这个目的使用传统图像里的区域分割技术&#xff0c;实际…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...