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

vue3从精通到入门4:diff算法的实现

Vue 3 的 diff 算法相较于 Vue 2 有了一些改进和优化,主要是为了应对更复杂的组件结构和更高的性能需求。

以下是 Vue 3 diff 算法在处理列表更新时的大致步骤:

  1. 头头比较:首先,比较新旧列表的头节点(即第一个节点)。如果它们相同(基于 key 判断),则复用该节点,并移动两个列表的头指针到下一个节点。

  2. 尾尾比较:然后,比较新旧列表的尾节点(即最后一个节点)。如果它们相同,也复用该节点,并移动两个列表的尾指针到前一个节点。

  3. 移动或创建节点:如果头头比较和尾尾比较都没有找到可复用的节点,Vue 会尝试在旧列表中查找与新节点匹配的节点。如果找到了,则移动该节点到正确的位置;如果没有找到,则创建一个新节点。

  4. 删除节点:最后,检查旧列表中是否有剩余的节点没有被复用或移动。如果有,说明这些节点在新列表中不再需要,因此将它们从 DOM 中删除。

前置节点后置节点比对:

前置节点(头头比较):

比较新旧列表的头节点(即第一个节点)。如果它们相同(基于 key 判断),则复用该节点,并移动两个列表的头指针到下一个节点。

   // 1. sync from start// (a b) c// (a b) d e// 处理相同的前置节点while (i <= e1 && i <= e2) {// 获取索引为 i 的 新老节点 n1 和 n2const n1 = c1[i]const n2 = (c2[i] = optimized? cloneIfMounted(c2[i] as VNode): normalizeVNode(c2[i]))// 判断n1和n2新老节点相同的话,进行节点的更新操作if (isSameVNodeType(n1, n2)) {patch(n1,n2,container,null,parentComponent,parentSuspense,namespace,slotScopeIds,optimized,)} else {// n1 和 n2 不是相同节点话,前置节点的处理结束break}// 循环比对下一对前置节点i++}

后置节点(尾尾比较):

比较新旧列表的尾节点(即最后一个节点)。如果它们相同,也复用该节点,并移动两个列表的尾指针到前一个节点。

// 2. sync from end// a (b c)// d e (b c)// 处理相同的后置节点while (i <= e1 && i <= e2) {// 从最后的节点开始查找,获取的相关节点n1 和 n2const n1 = c1[e1]const n2 = (c2[e2] = optimized? cloneIfMounted(c2[e2] as VNode): normalizeVNode(c2[e2]))// 如果 n1 和 n2 是相同类型节点的话,则进行节点的更新操作if (isSameVNodeType(n1, n2)) {patch(n1,n2,container,null,parentComponent,parentSuspense,namespace,slotScopeIds,optimized,)} else {// 当n1 和 n2 两个新老节点不相同时,处理结束break}e1--e2--}

当比对完前置节点和后置节点后,记录e1、e2、i这三个值,后面需要用到;

仅有新增节点:

在第一步和第二步处理完前后置节点,如果新节点中是仅有新增节点;

源码解析:

根据上图,当 i > e1 并且 i <= e2 就是仅有新增节点

 // 仅有新增节点: 当新节点和旧节点对比时,发现新节点仅有新增节点,只需要将新的节点遍历挂载到新的节点树上if (i > e1) {if (i <= e2) {const nextPos = e2 + 1const anchor = nextPos < l2 ? (c2[nextPos] as VNode).el : parentAnchorwhile (i <= e2) {patch(null,(c2[i] = optimized? cloneIfMounted(c2[i] as VNode): normalizeVNode(c2[i])),container,anchor,parentComponent,parentSuspense,namespace,slotScopeIds,optimized,)i++}}}

仅有卸载节点:

在第一步和第二步处理完前后置节点,如果新节点中是仅有卸载节点;

源码解析:

根据上图,当 i > e2 并且 i <= e1 就是仅有卸载节点

     // 仅有卸载节点:else if (i > e2) {while (i <= e1) {unmount(c1[i], parentComponent, parentSuspense, true)i++}}

乱序的节点:

源码解析:

else {const s1 = i // prev starting index 旧节点索引const s2 = i // next starting index 新节点索引// 5.1 build key:index map for newChildren// 新节点位置映射表, 在前后置节点比较完的中间其余节点都拿出来,放在这个表中const keyToNewIndexMap: Map<string | number | symbol, number> = new Map()for (i = s2; i <= e2; i++) {const nextChild = (c2[i] = optimized? cloneIfMounted(c2[i] as VNode): normalizeVNode(c2[i]))if (nextChild.key != null) {if (__DEV__ && keyToNewIndexMap.has(nextChild.key)) {warn(`Duplicate keys found during update:`,JSON.stringify(nextChild.key),`Make sure keys are unique.`,)}keyToNewIndexMap.set(nextChild.key, i)}}// 5.2 loop through old children left to be patched and try to patch// matching nodes & remove nodes that are no longer presentlet jlet patched = 0// 新节点与旧节点对比后,需要变更的数量const toBePatched = e2 - s2 + 1// 移动标识let moved = false// used to track whether any node has moved// 当前最远位置let maxNewIndexSoFar = 0// works as Map<newIndex, oldIndex>// Note that oldIndex is offset by +1// and oldIndex = 0 is a special value indicating the new node has// no corresponding old node.// used for determining longest stable subsequence// 新旧节点位置映射表,默认值:新节点需要处理的个数const newIndexToOldIndexMap = new Array(toBePatched)for (i = 0; i < toBePatched; i++) newIndexToOldIndexMap[i] = 0for (i = s1; i <= e1; i++) {const prevChild = c1[i]if (patched >= toBePatched) {// all new children have been patched so this can only be a removalunmount(prevChild, parentComponent, parentSuspense, true)continue}let newIndexif (prevChild.key != null) {// 从新节点位置映射表中找旧节点映射值newIndex = keyToNewIndexMap.get(prevChild.key)} else {// key-less node, try to locate a key-less node of the same typefor (j = s2; j <= e2; j++) {if (newIndexToOldIndexMap[j - s2] === 0 &&isSameVNodeType(prevChild, c2[j] as VNode)) {newIndex = jbreak}}}if (newIndex === undefined) {// 当旧节点在新节点位置映射表中没有找到,直接卸载unmount(prevChild, parentComponent, parentSuspense, true)} else {// 当旧节点在新节点位置映射表中找到,更改新旧节点映射表中的值newIndexToOldIndexMap[newIndex - s2] = i + 1// if (newIndex >= maxNewIndexSoFar) {maxNewIndexSoFar = newIndex} else {moved = true}patch(prevChild,c2[newIndex] as VNode,container,null,parentComponent,parentSuspense,namespace,slotScopeIds,optimized,)patched++}}// 5.3 move and mount// generate longest stable subsequence only when nodes have movedconst increasingNewIndexSequence = moved? getSequence(newIndexToOldIndexMap): EMPTY_ARRj = increasingNewIndexSequence.length - 1// looping backwards so that we can use last patched node as anchorfor (i = toBePatched - 1; i >= 0; i--) {const nextIndex = s2 + iconst nextChild = c2[nextIndex] as VNodeconst anchor =nextIndex + 1 < l2 ? (c2[nextIndex + 1] as VNode).el : parentAnchorif (newIndexToOldIndexMap[i] === 0) {// mount newpatch(null,nextChild,container,anchor,parentComponent,parentSuspense,namespace,slotScopeIds,optimized,)} else if (moved) {// move if:// There is no stable subsequence (e.g. a reverse)// OR current node is not among the stable sequenceif (j < 0 || i !== increasingNewIndexSequence[j]) {move(nextChild, container, anchor, MoveType.REORDER)} else {j--}}}}

相关文章:

vue3从精通到入门4:diff算法的实现

Vue 3 的 diff 算法相较于 Vue 2 有了一些改进和优化&#xff0c;主要是为了应对更复杂的组件结构和更高的性能需求。 以下是 Vue 3 diff 算法在处理列表更新时的大致步骤&#xff1a; 头头比较&#xff1a;首先&#xff0c;比较新旧列表的头节点&#xff08;即第一个节点&…...

(三)C++自制植物大战僵尸游戏项目结构说明

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/ErelL 一、项目结构 打开项目后&#xff0c;在解决方案管理器中有五个项目&#xff0c;分别是libbox2d、libcocos2d、librecast、libSpine、PlantsVsZombies五个项目&#xff0c;除PlantsVsZombies外&#xff0c;其他四个…...

动态规划专练( 279.完全平方数)

279.完全平方数 给你一个整数 n &#xff0c;返回 和为 n 的完全平方数的最少数量 。 完全平方数 是一个整数&#xff0c;其值等于另一个整数的平方&#xff1b;换句话说&#xff0c;其值等于一个整数自乘的积。例如&#xff0c;1、4、9 和 16 都是完全平方数&#xff0c;而 …...

京东商品详情API接口(商品属性丨sku价格丨详情图丨标题等数据)

京东商品详情API接口是京东开放平台提供的一种API接口&#xff0c;通过调用该接口&#xff0c;开发者可以获取京东商品的标题、价格、库存、月销量、总销量、详情描述、图片等详细信息。下面针对您提到的商品属性、SKU价格、详情图以及标题等数据&#xff0c;做具体介绍&#x…...

Springboot+Vue项目-基于Java+MySQL的校园周边美食探索及分享平台系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…...

折叠面板组件(vue)

代码 <template><div class"collapse-info"><div class"collapse-title"><div class"title-left">{{ title }}</div><div click"changeHide"> <Button size"small" v-if"sho…...

【Canvas技法】蓝底金字北岛诗节选(径向渐变色、文字阴影示例)

【效果图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>北岛诗选</title><style type"text/css">.c…...

【大语言模型】基础:TF-IDF

TF-IDF (Term Frequency-Inverse Document Frequency) 是一种用于信息检索与文本挖掘的统计方法&#xff0c;用来评估一个词对于一个文件集或一个语料库中的其中一份文件的重要性。它是一种常用于文本处理和自然语言处理的权重计算技术。 原理 TF-IDF 由两部分组成&#xff1…...

[开发日志系列]PDF图书在线系统20240415

20240414 Step1: 创建基础vueelment项目框架[耗时: 1h25min(8:45-10:10)] 检查node > 升级至最新 (考虑到时间问题,没有使用npm命令行执行,而是觉得删除重新下载最新版本) > > 配置vue3框架 ​ 取名:Online PDF Book System 遇到的报错: 第一报错: npm ERR! …...

蓝桥杯 — — 纯质数

纯质数 题目&#xff1a; 思路&#xff1a; 一个最简单的思路就是枚举出所有的质数&#xff0c;然后再判断这个质数是否是一个纯质数。 枚举出所有的质数&#xff1a; 可以使用常规的暴力求解法&#xff0c;其时间复杂度为&#xff08; O ( N N ) O(N\sqrt{N}) O(NN ​)&…...

OpenCV基本图像处理操作(三)——图像轮廓

轮廓 cv2.findContours(img,mode,method) mode:轮廓检索模式 RETR_EXTERNAL &#xff1a;只检索最外面的轮廓&#xff1b;RETR_LIST&#xff1a;检索所有的轮廓&#xff0c;并将其保存到一条链表当中&#xff1b;RETR_CCOMP&#xff1a;检索所有的轮廓&#xff0c;并将他们组…...

比特币突然暴跌

作者&#xff1a;秦晋 周末愉快。 今天给大家分享两则比特币新闻&#xff0c;也是两个数据。一则是因为中东地缘政治升温&#xff0c;传统资本市场的风险情绪蔓延至加密市场&#xff0c;引发加密市场暴跌。比特币跌至66000美元下方。杠杆清算金额高达8.5亿美元。 二则是&#x…...

使用SpeechRecognition和vosk处理ASR

SpeechRecognition可以支持多种模型语音转文字&#xff0c;感觉vosk还不错&#xff0c;使用起来也简单一些&#xff1b;百度也有PaddleSpeech&#xff0c;但是安装起来太麻烦&#xff0c;不是这个库版本不对就是那个库有问题&#xff0c;用起来不方便&#xff1b; 安装SpeechR…...

【Go】通道:缓冲通道和非缓冲通道

目录 通道的基本概念 缓冲通道 非缓冲通道 总结 通道的基本概念 在Go语言中&#xff0c;通道是一种特殊的类型&#xff0c;用于在goroutine之间传递数据。你可以将通道想象为数据的传输管道。通道分为两种类型&#xff1a; 非缓冲通道&#xff08;Unbuffered Channels&…...

Java中数组的使用

在Java编程中&#xff0c;数组是一种非常重要的数据结构&#xff0c;它允许我们存储相同类型的多个元素。对于初学者来说&#xff0c;理解数组的基本概念、初始化、遍历、默认值以及内存分配和使用注意事项是非常关键的。 一、数组的概念 数组是一个可以容纳多个相同类型数据…...

CAP5_Monday

A Set to Max (Easy Version) 给定数组 a 和 b&#xff0c;可以执行以下操作任意次 : 让 a l ∼ a r a_l\sim a_r al​∼ar​ 中的所有所有元素变成 a i a_i ai​ ( l ≤ i ≤ r ) (l\leq i\leq r) (l≤i≤r)&#xff0c; 其中 1 ≤ l ≤ r ≤ n 1\leq l \leq r \leq n 1≤…...

科大讯飞星火开源大模型iFlytekSpark-13B GPU版部署方法

星火大模型的主页&#xff1a;iFlytekSpark-13B: 讯飞星火开源-13B&#xff08;iFlytekSpark-13B&#xff09;拥有130亿参数&#xff0c;新一代认知大模型&#xff0c;一经发布&#xff0c;众多科研院所和高校便期待科大讯飞能够开源。 为了让大家使用的更加方便&#xff0c;科…...

SpringBoot基于RabbitMQ实现消息延迟队列方案

知识小科普 在此之前&#xff0c;简单说明下基于RabbitMQ实现延时队列的相关知识及说明下延时队列的使用场景。 延时队列使用场景 在很多的业务场景中&#xff0c;延时队列可以实现很多功能&#xff0c;此类业务中&#xff0c;一般上是非实时的&#xff0c;需要延迟处理的&a…...

Go语言使用标准库时常见错误

Go的标准库是一组增加和拓展语言的核心包。然而,很容易误用标准库,或者我们对其行为理解有限,导致产生了bug或不应该在生产级应用程序中某些功能。 1. 提供错误的持续时间 标准库提供了获取 time.Duration 的常用函数和方法,但由于 time.Duration 是 int64 的自定义类型,…...

UE5不打包启用像素流 ubuntu22.04

首先查找引擎中像素流的位置&#xff1a; zkzk-ubuntu2023:/media/zk/Data/Linux_Unreal_Engine_5.3.2$ sudo find ./ -name get_ps_servers.sh [sudo] zk 的密码&#xff1a; ./Engine/Plugins/Media/PixelStreaming/Resources/WebServers/get_ps_servers.sh然后在指定路径中…...

微带贴片天线基础计算

2GHz微带阵列天线&#xff0c;HFSS仿真模型&#xff0c;介质板为FR4&#xff0c;增益4.5dBi&#xff0c;驻波小于1.5。最近在捣鼓2GHz频段的微带阵列天线设计&#xff0c;用HFSS建模仿真时遇到不少有意思的问题。FR4板材这玩意儿看着普通&#xff0c;实际用在天线设计里真得小心…...

深入理解栈溢出:我是如何通过CSAPP的AttackLab实验重新认识缓冲区安全的

深入理解栈溢出&#xff1a;从AttackLab实验看现代系统安全防御博弈 当我在深夜的实验室里第一次看到Segmentation fault提示时&#xff0c;并没有意识到这行简单的错误信息背后隐藏着怎样的安全危机。作为计算机系统安全领域最经典的漏洞类型&#xff0c;栈溢出攻击在过去三十…...

市场比较好的显示屏模块供货商哪家强

市场比较好的显示屏模块供货商推荐在显示屏模块市场&#xff0c;众多企业各展所长&#xff0c;为不同行业提供着优质的产品。以下为您介绍十家市场上表现出色的显示屏模块供货商&#xff1a;杭州斡能电子有限公司&#xff08;杭州斡能&#xff09; 杭州斡能始创于2008年10月&am…...

KindEditor富文本编辑器:轻量级网页内容创作解决方案

KindEditor富文本编辑器&#xff1a;轻量级网页内容创作解决方案 【免费下载链接】kindeditor WYSIWYG HTML editor 项目地址: https://gitcode.com/gh_mirrors/ki/kindeditor 在当今Web开发中&#xff0c;内容编辑功能是许多网站的核心需求&#xff0c;但开发者常常面临…...

ChatTTS实战:从WAV到PT的高效转换技术解析

在语音合成和语音处理的工作流中&#xff0c;数据预处理是至关重要的一环。我们常常从麦克风、录音设备或公开数据集中获得最原始的WAV格式音频&#xff0c;但深度学习模型&#xff0c;尤其是基于PyTorch的模型&#xff0c;其“母语”是张量&#xff08;Tensor&#xff09;。因…...

一、硬件接线与配置

自动配料控制系统 S7-200SMART 与组态王6.55联机程序 COM3串口通讯 带运行效果视频 IO表 和 PLC接线图CAD 老规矩先看IO表——配料系统核心是4路称重传感器2台变频器控制下料速度。PLC的EM AE04模块接0-10V称重信号&#xff0c;EM DR32数字量模块控制接触器和报警灯。CAD接线图…...

LFM2.5-1.2B-Thinking-GGUF入门指南:Thinking模型输出后处理机制解析

LFM2.5-1.2B-Thinking-GGUF入门指南&#xff1a;Thinking模型输出后处理机制解析 1. 模型概述 LFM2.5-1.2B-Thinking-GGUF是Liquid AI推出的轻量级文本生成模型&#xff0c;专为低资源环境优化设计。该模型采用GGUF格式存储&#xff0c;配合llama.cpp运行时&#xff0c;能够在…...

Cosmos-Reason1-7B保姆级教程:从NVIDIA模型下载到浏览器界面可用全流程

Cosmos-Reason1-7B保姆级教程&#xff1a;从NVIDIA模型下载到浏览器界面可用全流程 本文面向想要快速上手Cosmos-Reason1-7B推理工具的初学者&#xff0c;无需深厚技术背景&#xff0c;跟着步骤操作即可完成本地部署和使用。 1. 工具简介&#xff1a;你的本地推理助手 Cosmos-…...

VMware安装RHEL9连接Xshell与Linux基础命令vim练习

1、在VMware上创建虚拟机以及安装RHEL9操作系统&#xff0c;使用ssh进行远程连接2、文件管理命令练习: 1(1)在/opt目录下创建一个临时目录tmp;2(2)在临时目录下创建一个文件&#xff0c;文件名为a.txt;3、vi/vim练习:完成如下步骤(1&#xff09;应用vi命令在/tmp文件夹下创建文…...

Python 入门第一课:为什么选择 Python?3 分钟搭建你的第一个程序

一、先聊点人话&#xff1a;为啥要学 Python&#xff1f; 说实话&#xff0c;当初我选编程语言的时候也纠结过。Java&#xff1f;太啰嗦。C&#xff1f;头都大了。JavaScript&#xff1f;浏览器里跑着玩还行… 直到我遇见了 Python。 这玩意儿有多友好&#xff1f; 这么说吧&…...