当前位置: 首页 > 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;实际…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...