虚拟DOM

182 阅读4分钟

什么是虚拟DOM

最早有FaceBook提出来的,在React和Vue中均有虚拟DOM的概念,为了减弱频繁大面积真实DOM排版与重绘引发的性能问题,即为了解决浏览器性能问题而被设计出来的。

  • 虚拟DOM,即VDOM,有时候称为VNode,可以看作是一个使用JAVASCRIPT模拟了DOM结构的树型结构,这个树型结构包含了整个DOM结构的信息,即用js对象来描述真实的DOM,相对于原生DOM更加轻量,另外配合diff算法,能最少的操作来更新DOM(即减少排版与重绘)。同时利用vue和react之类的框架支持除浏览器之外的其他平台。

为什么用虚拟DOM

  • 浏览器利用原生DOM本身有性能上缺陷,利用虚拟DOM能解决这些性能缺陷。
  • 浏览器的缓存有两种:协商缓存和强缓存(或叫彻底缓存)。
  • 浏览器缓存机制:浏览器缓存是浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一个页面时,浏览器就可以直接从本地磁盘加载文档。 协商缓存: 向服务器发送请求,服务器会根据这个请求的 request header 的一些参数来判断是否命中协商缓存,如果命中,则返回 304 状态码并带上新的 response header 通知浏览器从缓存中读取资源;

强缓存: 不会向服务器发送请求,直接从缓存中读取资源,在 Chrome 控制台的 network 选项中可以看到该请求返回 200 的状态码。

  两者的共同点: 都是从客户端缓存中读取资源。 区别:强缓存不会发请求,协商缓存会发送请求。

虚拟DOM与真实DOM的区别

  • 虚拟DOM不会进行排版与重绘操作
  • 虚拟DOM进行频繁修改,然后一次性比较并修改真实DOM中需要改的部分,最后并在真实DOM中进行排版与重绘,减少过多的DOM节点排版及重绘的损耗。
  • 真实的DOM频繁排版与重绘的效率是相当低的。
  • 虚拟DOM有效降低大面积(真实DOM节点)的排版与重绘,因为最终与真实DOM比较差异,可以只渲染局部。
虚拟DOM的损耗计算 总损耗 = 虚拟DOM增删改 + (与Diff算法效率有关)真实DOM差异增删改 + (较少的节点)排版与重绘
真实DOM的损耗计算   总损耗 = 真实DOM完全增删改 + (可能较多的节点)排版与重绘

从双缓存和MVC的角度来理解虚拟DOM

双缓存

image.png

而使用双缓存,可以先让你将计算的中间结果存放在另一个缓冲区中,等全部的结算结束,该缓冲区已经存储了完整的图形之后,再将该缓冲区的图形数据一次性复制到显示缓冲区,这样就使得整个图像的输出非常稳定。

 在这里,你可以把虚拟 DOM 看成是 DOM 的一个 buffer,和图形显示一样,它会在完成一次完整的操作之后,再把结果应用到 DOM 上,这样就能减少一些不必要的更新,同时还能保证 DOM 的稳定输出。 MVC模式

image.png

在该图中,我们可以把虚拟 DOM 看成是 MVC 的视图部分,其控制器和模型都是由 Redux 提供的。其具体实现过程如下:

图中的控制器是用来监控 DOM 的变化,一旦 DOM 发生变化,控制器便会通知模型,让其更新数据;

  • 模型数据更新好之后,控制器会通知视图,告诉它模型的数据发生了变化;
  • 视图接收到更新消息之后,会根据模型所提供的数据来生成新的虚拟 DOM;
  • 新的虚拟 DOM 生成好之后,就需要与之前的虚拟 DOM 进行比较,找出变化的节点;
  • 比较出变化的节点之后,React 将变化的虚拟节点应用到 DOM 上,这样就会触发 DOM 节点的更新;
  • DOM 节点的变化又会触发后续一系列渲染流水线的变化,从而实现页面的更新。

虚拟DOM的实现流程

先根据真实DOM生成一颗virtual DOM,当virtual DOM某个节点的数据改变后会生成一个新的Vnode,然后Vnode和oldVnode作对比,发现有不一样的地方就直接修改在真实的DOM上,然后使oldVnode的值为Vnode。

diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁。

image.png

微信图片_20220518145712.png

1652856931(1).png