2024年《Vue源码解读》深入浅出Vue的Diff算法(一),6年菜鸟开发面试字节跳动前端研发岗

最后

在面试前我花了三个月时间刷了很多大厂面试题,最近做了一个整理并分类,主要内容包括html,css,JavaScript,ES6,计算机网络,浏览器,工程化,模块化,Node.js,框架,数据结构,性能优化,项目等等。

包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。

  • HTML5新特性,语义化

  • 浏览器的标准模式和怪异模式

  • xhtml和html的区别

  • 使用data-的好处

  • meta标签

  • canvas

  • HTML废弃的标签

  • IE6 bug,和一些定位写法

  • css js放置位置和原因

  • 什么是渐进式渲染

  • html模板语言

  • meta viewport原理

  • C就是业务逻辑、交互逻辑,比如当用户输入完数据后,如何将数据处理并填充渲染到页面上去的过程,反之亦然;

在这个模式中C也就是Controller这一层其实非常薄弱,职能不强,View这一层倒反正非常厚,所有对DOM处理的操作都在这一层,一旦数据变动了就要去重新操作DOM,用设计模式的话说就是 耦合度非常高,如果业务有变动往往代码就要重写,并且还写不好…所以也就有了MVVM这种模式,那么这两种模式最大的区别是什么?

在回答这个问题之前,我先问个问题,DOM渲染页面之后,什么操作会对浏览器的性能产生较大影响?在我看来GUI 渲染线程中的重绘(Repaint)和回流(reflow)会对浏览器的性能产生较大影响,可能会有小伙伴不大清楚什么是重绘、什么是回流,这里简单说一下吧

  • 重绘: 当一些元素需要更新属性,而这些属性的更新仅仅影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘

  • 回流: 当页面布局发生变化,比如我们修改一个元素的宽高,这时候DOM树结构随之也会发生变化,而DOM树与渲染树是紧密相连的,DOM树构建完,渲染树也会随之对页面进行再次渲染,这个过程就叫回流

了解重绘和回流之后,那么我们就可以来说说为什么会有MVVM这种模式了,先说我的个人结论,我认为MVC和MVVM这两者本质上其实没多大区别,MVVM是脱胎于MVC的一种开发模式,传统MVC设计模式中针对DOM的操作几乎都是手动的,也就是需要开发人员去手动开发相关的控制代码,比如我们更新数据需要先获取到DOM,然后对DOM中的值进行覆盖,这也就导致了开发人员会频繁的去操作DOM,页面会频繁的在重绘和回流,MVVM这种模式就优化了这一步,它将Controller的职能完全放大,并且数据与页面DOM之间原则上不再有直接关联,通通交给Controller,包括对DOM的操作也都是框架自动去渲染,如下示例:

在这里插入图片描述

这么改的好处就是,开发人员可以专注于数据与业务的处理,C这一层就进行了一次进化,将DOM操作这些全部归纳到VM(ViewModel)里,VM的本质也会去操作DOM,但框架有最优秀的一批开发大佬写算法计算如何最优的去动态处理DOM,什么样的操作DOM消耗的性能最小,体验最好,那么 VM里面是如何做优化的呢,那就要说到这一小节的主角了,Virtual-dom

Virtual-dom


Virtual-dom,又叫虚拟DOM,本质上就是用JS对象在描述DOM结构, 为什么要这么干,因为操作DOM就会重绘与回流,就会增加浏览器压力,但是操作DOM却非常简单,举一个简单的例子

// html代码

换成虚拟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

最后

本人分享一下这次字节跳动、美团、头条等大厂的面试真题涉及到的知识点,以及我个人的学习方法、学习路线等,当然也整理了一些学习文档资料出来是给大家的。知识点涉及比较全面,包括但不限于前端基础,HTML,CSS,JavaScript,Vue,ES6,HTTP,浏览器,算法等等

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

前端视频资料:

字节跳动、美团、头条等大厂的面试真题涉及到的知识点,以及我个人的学习方法、学习路线等,当然也整理了一些学习文档资料出来是给大家的。知识点涉及比较全面,包括但不限于前端基础,HTML,CSS,JavaScript,Vue,ES6,HTTP,浏览器,算法等等

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

[外链图片转存中…(img-qrhBpijG-1715473689086)]

前端视频资料:
[外链图片转存中…(img-xHVwJoca-1715473689087)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值