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

news2024/11/24 9:21:39

前言

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT背后的技术可以给数据治理带来哪些神奇的效果?_光点科技

最近&#xff0c;由美国人工智能研究室OpenAI开发的全新“聊天机器人”ChatGPT火了。作为一款人工智能语言模型&#xff0c;它不仅能和人展开互动&#xff0c;还可以写文章、制定方案、创作诗歌&#xff0c;甚至编写代码、检查漏洞样样精通&#xff0c;上线仅两个月全球活跃用户…

Python雪花代码

前言 用python画个雪花玩玩&#xff0c;源码在文末公众号哈。 雪花类 class Snow(): #雪花类 def __init__(self): self.r 6 #雪花的半径 self.x ra.randint(-1000,1000) #雪花的横坐标 self.y ra.randint(-500,5…

剑指 Offer 10- I. 斐波那契数列[c语言]

目录题目思路代码结果该文章只是用于记录考研复试刷题题目 力扣斐波那契数列 写一个函数&#xff0c;输入 n &#xff0c;求斐波那契&#xff08;Fibonacci&#xff09;数列的第 n 项&#xff08;即 F(N)&#xff09;。斐波那契数列的定义如下&#xff1a; F(0) 0, F(1) 1 …

卷积神经网络-D2L

从全连接层到卷积 企业级理解卷积 不稳定输入 稳定输出 求系统存量 - 信号系统周围像素点如何产生影响 - 图像处理一个像素点如何试探 - 图像识别 好处&#xff1a; 平移不变性和局部性 图像卷积 import torch from torch import nn from d2l import torch as d2ldef try_…

Java高频面试题,ReentrantLock 是如何实现锁公平和非公平性的?

我先解释一下个公平和非公平的概念。 公平&#xff0c;指的是竞争锁资源的线程&#xff0c;严格按照请求顺序来分配锁。 非公平&#xff0c;表示竞争锁资源的线程&#xff0c;允许插队来抢占锁资源。 ReentrantLock 默认采用了非公平锁的策略来实现锁的竞争逻辑。 其次&…

SqlServer的LDF文件丢失, 如何仅用MDF文件恢复数据库呢?(已解决)

笔者的一个大小为2 TB的SQL Server的database的LDF文件在玩存储盘映射的过程中莫名其妙的丢失了. 好在MDF文件还在. 笔者慌了, Bruce Ye告诉笔者, 不用着急, 光用MDF也可以把数据库弄回来的. 笔者就问Bruce, 假设我可以容忍LDF中信息的丢失的话, 那么该如何恢复这个数据库呢?我…

快速搭建个人在线书库,随时随地畅享阅读!

前边我们利用NAS部署了个人的导航页、小说站、云笔记&#xff0c;今天&#xff0c;我们再看看怎么部署一个个人的在线书库。 相信很多朋友都在自己的电脑中收藏了大量的PDF、MOBI等格式的电子书籍&#xff0c;但是一旦换了一台设备&#xff0c;要么是无法翻阅&#xff0c;要么…

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

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

FortiTalk | “三英论安全”之OT安全热门话题解读

OT安全热门话题解读 在数字化转型时代&#xff0c;OT/IT融合已经成为主旋律&#xff0c;可能很多人还没有意识到“工厂”已经不是以前的“工厂”。从封闭走向互联、从现场走向远程、从手动走向自动&#xff0c;这种变革带来的不仅是便捷和效率&#xff0c;更潜藏着巨大的网络安…

【数据结构】基础:图的最短路径问题(附C++源码)

【数据结构】基础&#xff1a;图的最短路径问题&#xff08;附C源码&#xff09; 摘要&#xff1a;将会在数据结构专题中开展关于图论的内容介绍&#xff0c;其中包括四部分&#xff0c;分别为图的概念与实现、图的遍历、图的最小生成树以及图的最短路径问题。本文介绍图的最短…

LeetCode 105. 从前序与中序遍历序列构造二叉树 -- 数据结构基础

从前序与中序遍历序列构造二叉树 中等 1.9K 相关企业 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], i…

基于MATLAB的MIMO信道估计(附完整代码与分析)

目录 一. 介绍 二. MATLAB代码 三. 运行结果与分析 一. 介绍 本篇将在MATLAB的仿真环境中对比MIMO几种常见的信道估计方法的性能。 有关MIMO的介绍可看转至此篇博客&#xff1a; MIMO系统模型构建_唠嗑&#xff01;的博客-CSDN博客 在所有无线通信中&#xff0c;信号通过…

05- 线性回归算法 (LinearRegression) (算法)

线性回归算法(LinearRegression)就是假定一个数据集合预测值与实际值存在一定的误差, 然后假定所有的这些误差值符合正太分布, 通过方程求这个正太分布的最小均值和方差来还原原数据集合的斜率和截距。当误差值无限接近于0时, 预测值与实际值一致, 就变成了求误差的极小值。 fr…

【Calcite源码学习】ImmutableBitSet介绍

Calcite中实现了一个ImmutableBitSet类&#xff0c;用于保存bit集合。在很多优化规则和物化视图相关的类中都使用了ImmutableBitSet来保存group by字段或者聚合函数参数字段对应的index&#xff0c;例如&#xff1a; //MaterializedViewAggregateRule#compensateViewPartial()…

浏览器渲染原理JavaScript V8引擎

浏览器渲染原理 前言 在我们面试过程中&#xff0c;面试官经常会问到这么一个问题&#xff0c;那就是从在浏览器地址栏中输入URL到页面显示&#xff0c;浏览器到底发生了什么&#xff1f; 浏览器内有哪些进程&#xff0c;这些进程都有些什么作用&#xff1b;浏览器地址输入U…

【CentOS】有关时间的设置

目录环境信息date语法信息查看时间设置时间设置日期tzselecttimedatectl语法显示当前及所有时区修改时区hwclock语法读取硬件时钟使用硬件时钟设置系统时间使用系统时间设置硬件时钟如何理解硬件时钟和系统时钟环境信息 CentOS 7 date 语法信息 date --help用法&#xff1a…

Android - dimen适配

一、分辨率对应DPIDPI名称范围值分辨率名称屏幕分辨率density密度&#xff08;1dp显示多少px&#xff09;ldpi120QVGA240*3200.75&#xff08;120dpi/1600.75px&#xff09;mdpi160&#xff08;基线&#xff09;HVGA320*4801&#xff08;160dpi/1601px&#xff09;hdpi240WVGA4…

小白系列Vite-Vue3-TypeScript:011-登录界面搭建及动态路由配置

前面几篇文章我们介绍的都是ViteVue3TypeScript项目中环境相关的配置&#xff0c;接下来我们开始进入系统搭建部分。本篇我们来介绍登录界面搭建及动态路由配置&#xff0c;大家一起撸起来......搭建登录界面登陆接口api项目登陆接口是通过mockjs前端来模拟的模拟服务接口Login…

OpenStack手动分布式部署环境准备【Queens版】

目录 1.基础环境准备&#xff08;两个节点都需要部署&#xff09; 1.1关闭防火墙 1.2关闭selinux 1.3修改主机名 1.4安装ntp时间服务器 1.5修改域名解析 1.6添加yum源 2.数据库安装配置 2.1安装数据库 2.2修改数据库 2.3重启数据库 2.4初始化数据库 3.安装RabbitMq…

html网页加载ppt文件非ifram加载

今天有一个客户需求是加载一个ppt文件还要有翻页的效果&#xff0c;我搜索了很久也只有一个ifram加载。 所以我果断用了chtgpt然后发现了一个宝藏效果 代码如下&#xff1a; <!DOCTYPE html> <html> <head><title>PPT预览</title> </head>…