virtual DOM和真实DOM的区别_虚拟dom知多少

现在我们的项目中大多数都是用的react和vue等框架,我们都知道这些框架的主要核心之一是实现了虚拟dom。今天就让我们一起研究一下这个虚拟dom具体是如何实现的吧

什么是虚拟dom

虚拟dom(virtual-dom简称vdom)就是通过使用js来模拟真实的dom,通过这种技术,我们可以精准的改变我们需要改变的dom结构,而不是粗暴的将整个dom结构改变,从而减少dom开销。另一方面,dom结构用js来控制的话,我们就可以实现数据来控制结构的改变。比如我们的react。

虚拟DOM是react框架的非常重要的一个特性之一,vdom的推广也是得益于react的出现。主要是为了解决手动操作dom而带来的性能问题

为什么要用虚拟dom

首先,我们看一下浏览器在渲染一个HTML文件需要哪些步骤。

0ffa3796465b5ba577d146870fa8d364.png

所有浏览器的工作流程都差不多,大致分为这5个部分。创建DOM树 -> 创建CSSOM -> 运行JS -> 渲染树 -> 实现布局 -> 绘制页面

在render树和渲染dom树和css树的过程中,它们不是完全独立的,而是会有交叉。会造成一边加载,一遍解析,一遍渲染的工作现象。

在使用原生api或者用JQuery操作dom树的时候,浏览器会从构建DOM树开始从头到尾执行一遍流程。DOM操作非常昂贵,而js的运行效率非常高,可以用js来模拟DOM结构,从而减少dom结构的操作。

来看看为什么操作真实dom是一件非常耗费性能的事情

9a1c6e3dc2d5711c7ab45994536f55cc.png

795e655c427e9be46e7192a512886ef7.png

OMG,我们看到一个div竟然有3000多个属性,还要不要活了。果然还是老话说的对,“宁可js操作一万遍,不能操作dom一遍”。所以虚拟dom就是为了解决dom结构操作消耗太大,影响浏览器性能的问题

即使计算机硬件一直在更新迭代,但也扛不住dom结构这么任性的造呀,频繁操作还是会出现页面卡顿,影响用户的体验。

虚拟dom如何实现

上面说的问题这么严重,要怎么解决才好呢?正所谓“卤水点豆腐,一物降一物”说的就是这个道理,如此邪恶的耗费性能,不能放任不管,虚拟dom就是为了降服这个问题而诞生的。接下来,我们介绍一下虚拟dom是如何实现的吧

此篇文章以snabbdom为例子来说一下虚拟dom是如何实现的。

为啥选择用snabbdom.js库来介绍虚拟dom呢?

  1. snabbdom.js库是专门实现虚拟dom,源码非常简短
  2. 非常火爆的vue实现虚拟dom就是借鉴的snabbdom.js库实现的

首先,我们看一下snabbdom官方给的例子

de0b9883ee0ce9f649443be02ff47f1c.png

这里可以列出来两个核心函数,即h()函数和patch()函数。首先我们看一下h()函数
h()函数其实主要是提供了一个工具函数,让我们方便的创建一个vnode对象,实现虚拟dom结构。

来个栗子: 一般我们在html下的DOM结构是这样的

c0496eafc751b953d9b480a0442888f7.png

h()函数的实现方式是这样的:

5b97a6de03beafedaf967d4acfa78f22.png

经过解析之后的结果:

43de475958a18f568cc35083e22fc81a.png

值得注意的一点是: JS模拟的DOM节点并没有模拟实际DOM节点上的属性、方法,而只是模拟了其中一部分和数据相关的属性和方法;从而达到减小耗费性能的目的

现在有这样一个场景:有个列表的信息是序号、姓名、地址,如下样子

d585a67e0d3a754decf644388e1a0682.png

现在我们想把第二个数据的序号从222改成555,将第三条数据的广东改成米国,我们想的就是,只要将第二条的222修改成555,第三条的广东修改成米国,别的保持不变就可以了,对不对!!!但是,实际上是这样的吗?

42597439e745cd1699c79a44296dfe66.gif

可以看到,我们需要的数据已经发生变化,但是,我们同时观察dom结构的变化发现,ul的结构闪烁了一下,说明dom结构是被重新删除又重新创建的,而不是只修改我们想要修改的内容,这样的操作无遗就是操作了我们昂贵的dom结构,这样的操作万万使不得呀

现在我们通过一个实例看看虚拟dom是否实现了我们想要的结果?

我们现在的是这个样子的,如下图

06bb72f585494fc1154ff28e4360bcb4.png

我们希望点击button的时候,可以将item 2 修改成item 哈哈,然后在添加一个item3,如下图

48f4075bf64400d3964965390db83b8a.png

通过操作虚拟dom,还是不是以前那种简单粗暴的方法,直接将整个item系列删除,然后在创建呢?让我们看一下实际的渲染过程是啥样的吧

1766b5e7d337eaeef81204da9a4b7041.gif

哎呦,虚拟dom果然是优秀。通过点击button,我们可以看到,这次的操作只是修改了我们想让它改变的部分,我们不想改变的结构,根本就没有发生任何变化。显然,已经达到了我们预期的结果,让我们看一下是如何实现的吧

a6d761e17408847fb26e6f478b8991e4.png

通过上面的对比实例我们可以看出,由于实际dom的渲染过程是先删除原来的结构在创建新的dom结构,而且每一个节点上的属性又特别多,如果我们大面积操作dom结构的话,就会出现多余加载dom结构的现象,而且也会引发性能问题,而用js实现虚拟dom,则会减少dom操作。

接下来,我们看一下snabbdom实现虚拟dom的核心api是什么呢

虚拟dom的核心api

snabbdom实现虚拟dom有三个比较核心的部分分别为:h()函数,patch()函数和diff算法

h()函数的作用是将js模拟的DOM结构,转换成虚拟DOM结构,再通过patch()函数将虚拟DOM转换成真实的DOM结构渲染到页面中,接下来,我们看看patch函数是做什么的呢?

path()函数的执行分为两个阶段。两个阶段都传递两个参数

第一个阶段是虚拟DOM首次渲染。patch(container,vnode),放在真是DOM的container和生成的vnode,此时此刻patch()函数的主要作用是将初次生成的真实的DOM结构挂载到指定的container上。

第二个阶段是更新DOM节点。patch(vnode,newVnode),此阶段的patch()函数,根据vnode和newVnode传进来的参数判断DOM节点是否发生变化,来改变DOM结构,那么patch函数是如何实现对比两个vnode结构是否发生变化,从而对真实的DOM节点进行更新呢?这里就涉及到diff算法了

diff算法也是虚拟dom实现过程中一个非常核心的部分,通过对比新旧dom,从而判断是否要改版dom结构。后续会有diff算法详细介绍的文章,这里就不多赘述了

为何要减少dom开销

我们为什么要用虚拟dom来减少dom的开销呢?

首先,DOM的渲染和浏览器的架构是有关系的,在webkit的浏览器架构中DOM模块和js的模块是互相独立且分割的,因此每次操作DOM的开销要比单纯的操作一次js开销要大。

第二: 在整个前端项目中,浏览器的重绘和重排非常耗费性能,减少重绘和重排也是我们前端需要做的优化。

最后:像一些大型的项目,销毁dom结构是非常常见的事情,在之前的jQuery时代,总有一些渲染列表的行为存在,可想而知,减少dom操作在我们前端世界有多么重要。

现在我们直观的看一下,用实际dom操作和虚拟dom操作,在dom渲染的过程中,耗费时间的大小
题目: 页面上有1000个dom结构,现在想要改一下前10个dom,如图所示:

329a5fe705e9dea9c712809b78cc0570.png

点击修改后,前10个发生变化,看一下真实dom和虚拟dom在渲染过程中,需要的时间:

d852892f3c085aea8734d144a3976e97.png

6fbd1a3c8bc11100e0af05625b957d25.png

通过实例我们可以看到,操作真实dom是虚拟dom操作时间的10倍多。而且这才是修改10个dom,平时我们做的项目,不止是修改10个dom这么简单,可以看出,减少dom开销,我们势在必行

虚拟dom减少dom的开销有什么好处呢?

虚拟dom是为了解决浏览器性能而设计出来的,就像之前的更改dom结构的例子,虚拟dom不会立即更改dom结构,而是将更新的diff内容保存到一个js对象中,最终将这个js对象一次性渲染到dom树上,从而减少dom结构的运算量。所以,用JS对象模拟DOM节点的好处是,操作js中的更新对象,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制。

文章写到这里就已经接近尾声了,希望这篇文章能帮助小伙伴们进一步的了解虚拟DOM。既然大家都看到这里了,不妨在动动手给点个赞鸭!同时,再安利大家一句话

真正最重要的任务永远只有一个——那个真正对你目标实现有帮助的任务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值