什么是虚拟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
双缓存
而使用双缓存,可以先让你将计算的中间结果存放在另一个缓冲区中,等全部的结算结束,该缓冲区已经存储了完整的图形之后,再将该缓冲区的图形数据一次性复制到显示缓冲区,这样就使得整个图像的输出非常稳定。
在这里,你可以把虚拟 DOM 看成是 DOM 的一个 buffer,和图形显示一样,它会在完成一次完整的操作之后,再把结果应用到 DOM 上,这样就能减少一些不必要的更新,同时还能保证 DOM 的稳定输出。 MVC模式
在该图中,我们可以把虚拟 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打补丁。