不会 Vue,但不影响我学 diff 算法

本文探讨了Diff算法在前端开发中的作用,尤其是对于Vue和Snabbdom等框架的重要性。首先介绍了虚拟DOM的概念,然后详细讲解了Diff算法在不同框架中的应用及其区别,包括比较目标、结果用途和比较方式。文章通过分析Snabbdom的源码,解释了框架如何利用Diff算法优化性能。最后讨论了使用唯一标识作为key的重要性,并提出了关于虚拟DOM是否一定优于真实DOM的思考。
摘要由CSDN通过智能技术生成

前言

现在社会各行各业大都面临着寒冬,互联网行业最近还出现了裁员潮,导致前端是越来越卷,普通学校的应届生不仅要跟985、211毕业的学生以及研究生进行竞争,甚至还需要和最近刚被裁的、有了几年工作经验的程序员竞争,害,趁我还年轻,赶紧努力考个公吧😭

玩笑归玩笑,但是现在就业形势确实严峻,前端面试时考查的难度也越来越大,面试官会问很多关于框架原理的知识点以区分候选人的水平和学习能力,而 diff 算法就属于面试中的高频问题,下面我们就来了解一下 diff 算法的核心思想,希望能让大家再被问到 diff 算法的时候能更加自信~

虚拟 DOM

在学习 diff 算法之前,我们必须要先清楚虚拟 DOM 的概念,因为 Vue 中的 diff 算法比对的不是别人,正是虚拟 DOM,那虚拟 DOM 到底是什么呢?(面试的时候可能会问)

虚拟 DOM 是用来表示真实 DOMJS 对象,该对象并没有真实 DOM 那么多的属性,它有的只是个别用来描述真实 DOM 的属性,比如真实 DOM 的元素类型、其对应的子元素(也是虚拟 DOM)等等,下面我们先来看一下 Vue 中的虚拟 DOM 到底长什么样?

<ul id='text-list'><li class="item1">你好呀</li><li class="item2">我是xxx</li><li class="item3">我们一起学习前端吧~</li>
</ul> 

上面是我们再熟悉不过的一段 html 段落,看看它们被转为虚拟 DOM 之后会变成什么样吧~🤩

{ tagName: 'ul', props: { id: 'text-list'},children: [{tagName: 'li', props: { class: 'item1' }, children: ['你好呀']},{tagName: 'li', props: { class: 'item2' }, children: ['我是xxx']},{tagName: 'li', props: { class: 'item3' }, children: ['我们一起学习前端吧~']}]
} 

果不其然,和我们说的一样,虚拟 DOM 就是一个 JS 对象,其上面的属性不多,都是用来描述真实 DOM 的结构的,比如说 tagName 是对应的元素名,props 是添加到元素上的属性,children 是由其子元素所组成的数组,每一个子元素也都是一个完整的虚拟 DOM

Diff 算法

介绍完了虚拟 DOM 之后,我们终于可以来讲讲什么是 diff 算法了,相信很多开发者都听过这个名词,但很多人会误认为 diff 算法是 React 或者 Vue 这种框架发明的,其实并不是,diff 很早就有了,它就是一种用来寻找两者差异的算法,那框架中的 diff 算法和传统的有什么区别呢?

1. 比较的目标不同

在框架中使用 diff 算法比对的目标是虚拟 DOM,这是在前端框架中才有的概念,但是最终的目的都是一样的,就是为了找出两者的不同,所以也可以将 diff 算法理解成专门用来找不同的算法

2. 比较结果的用处不同

在其它应用场景中使用 diff 算法可能只是为了知道双方是否完全相同,但是在框架中,在虚拟 DOM 的基础上,diff 算法判定为类型相等的节点可以进行复用,判定为不同的节点则会删除重建,这也是 diff 算法最核心的思想—复用

3. 比较的方式不同

虚拟 DOM 从形状上来看就是一棵树, 新旧虚拟 DOM 进行比对的时候,每一层级的节点只会和同层级的节点进行比较,不会跨层级比较,但这样不就做不到完全复用了吗?其实这是出于性能考虑的最佳方案,如果旧虚拟 DOM 上面的一个节点要和新虚拟 DOM 的所有节点进行比较,虽然可以最大程度上的复用节点,但是同时也会因为比较次数过多而大量的消耗性能,为什么那么说呢?

假如旧树上有 n 个节点,每个节点都需要和新树上的 n 个节点进行比较,找到不同的节点之后还需要进行各种操作(替换、删除、增加,时间复杂度为 O(n)),这样一来,新旧节点使用 diff 算法比较的时间复杂度就为 O(n^3),相当于三重 for 循环,这样太消耗性能了,于是框架对传统的 diff 算法进行了改造,选取了一种折中的方式——同级比较

如下图所示,只有在同一层的节点才会进行比较,而且只比较相同位置的节点,这样时间复杂度就降低到了 O(n)。如果一个节点在比对的时候判定为不相同,并且它还有子节点,那该节点会被直接删除,而不深度遍历子节点进行比较

Snabbdom 源码分析

看到这个小标题你可能有点懵,这篇文章不应该是讲 diff 算法的吗?在介绍框架的 diff 算法之前,我们必须要知道 Vue2 并没有选择自己重新造一套 Virtual-DOM 的算法,而是在 Snabbdom 这个库的基础上构建了一个嵌入了框架本身的 fork 版本

所以说,Vue2diff 算法就是在原有 Snabbdom 进行改造得到的,而 Vue3diff 算法又是在 Vue2 的基础上改良的,Reactdiff 算法又和 Vue 大同小异,有异曲同工之妙。搞懂了 Snabbdom 的原理,框架中的 diff 算法自然也就理解了,虽然有部分逻辑不一致,但核心思想还是很相似的;还有一个原因就是 Snabbdom 不仅涵盖了 diff 算法的核心思想,而且由于源码并不涉及框架中的额外操作,所以阅读起来会简单很多

以上就是这篇文章为什么这篇文章不去专门解读 VueReact 的源码,而是去研究 Snabbdom 源码的原因,这也对应了本篇文章的标题:不会 Vue,但不影响大家学习 diff 算法,因为其不是一个具体的东西,它只是一种思想,不一定只在 VueReact 这样的框架中才会应用到

h 函数

框架都有一个将开发者书写的代码转换为虚拟 DOM 的函数,比如在 React 中,jsx 语法是 React.createElement 的语法糖,虚拟 DOM(在 React 中称为 react element)就是该函数创建出来的,而 Snabbdom 创建虚拟 DOM 用的则是 h

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值