2024年最全《Vue源码解读》深入浅出Vue的Diff算法(一)(1),掌握这套精编Web前端高级面试题解析

总结

=============================================================

从转行到现在,差不多两年的时间,虽不能和大佬相比,但也是学了很多东西。我个人在学习的过程中,习惯简单做做笔记,方便自己复习的时候能够快速理解,现在将自己的笔记分享出来,和大家共同学习。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

个人将这段时间所学的知识,分为三个阶段:

第一阶段:HTML&CSS&JavaScript基础

第二阶段:移动端开发技术

第三阶段:前端常用框架

  • 推荐学习方式:针对某个知识点,可以先简单过一下我的笔记,如果理解,那是最好,可以帮助快速解决问题;如果因为我的笔记太过简陋不理解,可以关注我以后我还会继续分享。

  • 大厂的面试难在,针对一个基础知识点,比如JS的事件循环机制,不会上来就问概念,而是换个角度,从题目入手,看你是否真正掌握。所以对于概念的理解真的很重要。

换成虚拟DOM后,差不多就是类似于这种

{

tagName:“div”,

children:[

{

tagName:“a”,

href:“oliver.blog.csdn.net”

}

]

}

每次如果要渲染页面,只需要根据虚拟DOM树就可以去渲染了,因此,在MVVM中每一次变更数据后,对应的虚拟DOM树节点上的属性也会跟着变,最后根据这个树再统一去渲染页面,这样就可以大幅提高性能,可能有小伙伴还是不大明白,使用虚拟DOM后怎么就提高性能了,再举一个实际一点例子吧:

比如在一次操作中,我门需要更新20个DOM节点,浏览器在收到第一个DOM更新的请求后并不知道还有19次更新的操作,因此浏览器会马上执行流程,最终执行20次。例如,第一次计算完,紧接着下一个DOM更新请求,而在第二次DOM更新中这个节点的值就变了,这也就导致了第一次计算结果白白浪费了。即使计算机硬件一直在迭代更新,操作DOM的代价仍旧是昂贵的,频繁操作还是会出现页面卡顿,影响用户体验;

使用虚拟DOM后就会变成这样:

在一次操作中有20次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这20次更新的diff内容保存到本地一个对象中,最终将这个JS对象一次性更新到DOM树上,再进行后续操作,避免大量无谓的计算量。所以,虚拟DOM节点的好处很明显,页面的更新可以先全部反映在JS对象(虚拟DOM)上,操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制。

​(注意:这里强调了是一次操作)

到这里,相信小伙伴应该能明白Virtual-dom是什么以及它的优点了吧,在Virtual-dom中如何比对新节点和老节点的算法,就是我们的主角Diff算法;

其他优势


其实Virtual-dom的优势远远不止性能上的提升,甚至正因为它的存在,使得JavaScript的跨端再次提升了一个档次,因为通过虚拟DOM我们完全可以识别到页面元素的组成以及样式

在这里插入图片描述

通过将传统的HTML,CSS,JavaScript转成Virtual-dom,而Virtual-dom就像是一种规范、规则化的标准数据,这种数据描述了整个页面上所有的元素属性,之后在对应的端上反译,达到跨端的目的;

小结


在MVVM的开发模式中引入了Virtual-dom这个概念,它用JS对象描述了整个DOM树,在更新DOM之前先统一由Virtual-dom进行处理,最终一次性更新到DOM上,这样便极大的提升了浏览器性能,这Diff算法便是Virtual-dom中比对新老节点的算法;

Diff算法

================================================================

简介


总算介绍到Diff算法了,上文我们说到,Diff算法其实是用在Virtual-dom里的,在MVVM的开发模式中新增了一层抽象层用来模拟DOM结构,而Diff算法就是用来比对计算,比对新旧两个Virtual-dom里哪些节点发生了变化,仅针对这些发生变化的DOM节点做出更新即可;

Diff的策略


按层级diff比对

先说说Diff算法在MVVM框架中的比对策略吧,毕竟新旧两个Virtual-dom的比对不是瞎比对,看个图

在这里插入图片描述

在Vue或者说是React中都是遵循的同层级比对的策略,也就是说,旧Virtual-dom第一层蓝色只与新Virtual-dom的第一层做比对,旧Virtual-dom第二层紫色只与新Virtual-dom的第二层做比对,通过统计发现只有很少一部分情况会出现因为操作整个DOM结构都发生了更新,绝大多数情况都是DOM的层级不会变更;

按类型diff比对

这个怎么理解呢,举个例子,在Vue或者React中都有组件,diff算法在比对的时候如果发现组件的类型不一样了,那么这个组件包括其子组件都会被销毁,替换成新组件,而不会费时费力的去继续比对其子组件是否发生变化

在这里插入图片描述

比如这个例子中第一层的组件类型是三角形,它引用了两个子组件,经过变化后第一层的组件类型变成了五边形,但是子组件没有变化,这是diff不会去说因为只要第一层变化了,子组件都没有变因此只改变第一层的组件,保留第二次的三角,它会销毁整个蓝色三角以及其所有子组件,整体替换成五边形,并且新建了两个子组件;

执行流程分析


现在还不看源码,还是先弄明白Diff算法的执行过程,源码可以放到下一篇博文进行逐行分析,先看一下图例吧,图例里就是假设需要比对的新旧节点

在这里插入图片描述

先说一下含义:上面一排,代表的是旧的节点,下面一排,代表的是新的节点,大圆圈代表的Virtual-dom也就是虚拟DOM,小圆圈代表的是虚拟DOM对应的真实DOM;

当比对开始后,Diff算法会分别给这两个节点序列标注oldStartIdx、oldEndIdx、newStartIdx、newEndIdx的指针,标记完大致如下:

在这里插入图片描述

换句话说就是分别标记了起始位置和结束位置,标记结束就是正式开始比对逻辑;

第一步:比对oldStartIdx和newStartIdx

比对是会比对旧Virtual-dom的oldStartIdx和新Virtual-dom的newStartIdx的节点是否是同一个**,**也是如下图的比对

在这里插入图片描述

结果发现旧Virtual-dom的oldStartIdx和新Virtual-dom的newStartIdx的节点是同一个,那么**oldStartIdx和newStartIdx会都向后移动一位,变成如下所示**

在这里插入图片描述

继续比对第二个节点,也就是节点B和节点E,这是Diff发现节点B和节点E并不是同一个节点,那么此时就会去比对endIdx

第二步:比对oldEndIdx和newEndIdx

和startIdx一样,比对是会比对旧Virtual-dom的oldEndIdx和新Virtual-dom的newEndIdx的节点是否是同一个** ,**也是如下图的比对

在这里插入图片描述

比对结果发现旧Virtual-dom的oldEndIdx和新Virtual-dom的newEndIdx的节点是同一个,那么此时endIdx也会有startIdx一样往前移动1位

在这里插入图片描述

此时会进入第三个循环,继续比对旧Virtual-dom的oldStartIdx和新Virtual-dom的newStartIdx的节点是否是同一个,此时oldStartIdx和newStartIdx不是同一个,那么就继续去比对旧Virtual-dom的oldEndIdx和新Virtual-dom的newEndIdx,发现也不是同一个,那么此时会进行第三种比对,比对oldSatrtIdx和newEndIdx

第三步:比对oldSatrtIdx和newEndIdx

这一步比对也就是会比对oldSatrtIdx和newEndIdx,如图

在这里插入图片描述

比对结果发现oldSatrtIdx和newEndIdx是同一个节点,但是位置变化了,那么此时diff就会将B的位置进行转移重新排序,调整位置如下

在这里插入图片描述

并且,在转移的同时oldSatrtIdx和newEndIdx的位置也会分别移动一位,变成如下所示

在这里插入图片描述

之后继续进行新的一轮比对:

  1. 比对oldSatrtIdx和newStartIdx是否是同一个节点,发现不是,继续比对;

  2. 比对oldEndIdx和newEndIdx是否是同一个节点,发现不是,继续比对;

  3. 比对oldStartIdx和newEndIdx是否是同一个节点,发现不是,继续比对;

  4. 此时会出现一种新的比对方式,比对oldEndIdx和newStartIdx是否是同一个节点

第四步:比对oldEndIdx和newStartIdx

这一步就是比对oldEndIdx和newStartIdx是否是同一个节点,发现还不是,如果啊,如果发现oldEndIdx和newStartIdx是同一个节点,那么Diff会将这个节点调整位置,移动到oldStartIdx这个节点的前面;但是如图所示的例子中oldEndIdx和newStartIdx并不是同一个节点,那么此时会进行遍历操作;

第五步:遍历oldStart到oldEndIdx

变了操作大致就是:Diff会将oldStart到oldEndIdx之间所有的节点与newStartIdx节点进行逐一比对,看看是否有相同的,如果有相同的,调整位置,位置在oldStart的前面

第六步:新创建节点

这一步是存在于没有相同节点是的操作,如图所示,当比对结束后,发现E节点不存在旧Virtual-dom中,那怎么办,此时diff会创建一个节点,节点的位置在oldStartIdx的位置之前

在这里插入图片描述

在完成这一步之后,newEndIdx会往前移动一位,变成这样

在这里插入图片描述

这时候,发现newEndIdx已经小于newStartIdx了,这就代表旧Virtual-dom与新Virtual-dom之间的比对已经结束了;

第七步:清理旧节点

这一步当中会将oldStartIdx与oldEndIdx之间所有节点删除,并将老的虚拟节点删除,变成这样

在这里插入图片描述

这样,新的结果就出现,比对结束;

ES6

  • 列举常用的ES6特性:

  • 箭头函数需要注意哪些地方?

  • let、const、var

  • 拓展:var方式定义的变量有什么样的bug?

  • Set数据结构

  • 拓展:数组去重的方法

  • 箭头函数this的指向。

  • 手写ES6 class继承。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

微信小程序

  • 简单描述一下微信小程序的相关文件类型?

  • 你是怎么封装微信小程序的数据请求?

  • 有哪些参数传值的方法?

  • 你使用过哪些方法,来提高微信小程序的应用速度?

  • 小程序和原生App哪个好?

  • 简述微信小程序原理?

  • 分析微信小程序的优劣势

  • 怎么解决小程序的异步请求问题?

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值