虚拟 DOM(VDOM)是一个编程概念,它是真实 DOM 的一个轻量级副本。它以 JavaScript 对象的形式存在,可以更快速地处理和计算,因为操作 JavaScript 对象比操作真实 DOM 快得多。
在 Web 开发中,我们经常需要通过 JavaScript 修改 DOM,而大量的 DOM 操作是非常昂贵的。因此,为了解决这个问题,我们引入了虚拟 DOM 的概念。
使用虚拟 DOM,我们可以在内存中进行复杂操作,然后一次性将最终的结果反映在真实 DOM 上,从而避免频繁操作真实 DOM 带来的性能消耗。
那...到底什么是虚拟 DOM ?
想象一下你正在构建一个房子,你可能会先制作一个模型,这个模型就像是虚拟 DOM,它是实际建筑(真实 DOM)的一份轻量级的复制品。
模型是由小型的、易于操作的部件(比如乐高积木)组成的,你可以轻松地在模型上添加、移除或更改部件,看看效果如何。
假设你想改变房子的一部分,比如增加一个窗户。
在实际的建筑上做这个改动可能需要很多工作:你需要拆掉墙,安装窗户,然后重新粉刷。但在模型上做这个改动就容易多了:你只需要在正确的位置上放置一个新的窗户积木即可。
在你对模型进行了一系列改动之后,你可以查看模型,看看新的设计是否满足你的需求。如果满足,你就可以按照模型的改动在实际建筑上进行同样的改动。这个过程就相当于将虚拟 DOM 的改动应用到真实 DOM 上。
因此,虚拟 DOM 作为一个中间层,使得我们可以在不直接操作真实 DOM 的情况下进行复杂的界面操作。这种方式避免了频繁地、直接操作真实 DOM,从而大大提高了性能。
"重绘"过程就好比根据我们修改过的模型去更新实际的建筑。在这个过程中,我们会找出虚拟 DOM(模型)和真实 DOM(实际建筑)之间的差异,然后在真实 DOM 上进行相应的操作,使其与虚拟 DOM 的状态保持一致。
虚拟 DOM 的主要步骤是:
- 创建一个虚拟 DOM 的副本:我们创建一个和真实 DOM 完全一样的虚拟 DOM,这就是我们将要修改的地方。
- 修改虚拟 DOM:我们通过修改虚拟 DOM 来实现我们的功能,比如添加、修改和删除元素。
- 计算差异:一旦我们完成了所有的修改,我们就会计算新的虚拟 DOM 和旧的虚拟 DOM 之间的差异。这个过程叫做"diffing"。
- 更新真实的 DOM:最后,我们会把这些差异应用到真实的 DOM 上,这样用户就能看到这些改变了。这个过程叫做"重绘"。
在传统的开发中,如果没有使用像 React 或 Vue 这样的前端框架,那么虚拟 DOM 的概念可能不会直接应用。在这种情况下,开发人员需要直接操作 DOM,为元素添加事件监听器,或者使用例如 jQuery 这样的库来简化这些操作。
但是,这种方式可能会引发一些性能问题,因为频繁的 DOM 操作可能会导致浏览器重新渲染页面,消耗大量的计算资源。
Vue 中的虚拟 DOM 你了解多少 ?
Vue 使用 JavaScript 对象结构来模拟真实 DOM,这就是所谓的虚拟 DOM。每个 JavaScript 对象(被称为 VNode)都代表了一个 DOM 节点。这个对象包含了元素的类型(比如 'div','span'等)、元素的属性(如 class、style 等)、元素的子节点等信息。
每次数据发生变化时,Vue 都会重新生成一个新的虚拟 DOM 树。然后,Vue 会将新的虚拟 DOM 树与旧的虚拟 DOM 树进行对比,这就是 "diffing" 过程。这个对比过程是如何进行的呢?
Vue 使用了一种高效的 diff 算法。它只会在同一层级进行节点的对比,不会跨越层级去对比,这大大提高了对比的效率。Vue 首先会比较两棵树的根节点,如果根节点不同,那么整棵树都将被销毁并重建。如果根节点相同,那么 Vue 就会进一步比较子节点。
在比较子节点时,Vue 使用了一种被称为 "双端比较" 的技术。
它会同时从子节点列表的两端开始比较,将相同的节点快速匹配掉,然后再处理中间的部分。这种方式可以更高效地处理常见的 DOM 操作,如列表的反转、头尾部的插入和删除等。
当 Vue 找出了两棵树之间的差异后,它就会生成一系列的 "patches"(补丁),每个补丁描述了一个具体的 DOM 操作,比如创建一个新节点、删除一个旧节点、更新节点的属性等。这就是 "patching" 过程。最后,Vue 会把这些补丁应用到真实的 DOM 上,从而使真实 DOM 的状态与新的虚拟 DOM 树的状态保持一致。
所以
虚拟 DOM 比直接操作 DOM 更高效!
虚拟 DOM 其实主要是减少浏览器的重排(reflow)和重绘(repaint)操作
那么,什么是重排和重绘呢?
重绘和重排都是浏览器渲染页面的一部分。你可以把它们想象成浏览器的画师和建筑师。当网页上的一些元素需要改变样子或位置时,这两位就需要上场了。
重绘——画师
就像画师给画上色一样,重绘就是当元素的外观(比如颜色、阴影等)发生改变,但布局和尺寸没有变化的时候,浏览器需要对这个元素重新"上色"。这个过程就叫做重绘。就像给一幅画换颜色一样,它只影响那个元素,不会影响到其他的部分。
重排——建筑师
这就像建筑师重新设计房子的布局一样。当元素的尺寸、位置或者某些属性(比如宽度、高度、边距等)发生变化,就会影响到元素在页面上的布局。浏览器就需要重新计算元素的位置和大小,这个过程就叫做重排。这比重绘要复杂,因为它可能会影响到页面的其他部分。
为了提高性能,我们希望尽量减少重绘和重排的次数。这就是虚拟 DOM 的作用,它在内存中预先计算好所有的改变,然后一次性把这些改变反应到页面上,这样可以避免不必要的重绘和重排。
难道虚拟 DOM 就没有什么缺点吗?所有应用都可以使用它吗?
理论上来说,虚拟 DOM 的优势在于它可以有效地处理大量的 DOM 操作,尤其是在复杂的用户界面和频繁的 UI 更新中。然而,就像任何技术一样,虚拟 DOM 并不是万能的,其效用取决于具体的使用场景。
对于一些小型应用,或者那些 DOM 操作较少的应用,虚拟 DOM 可能会引入不必要的复杂性和开销。在这些情况下,直接操作 DOM 可能会更简单、更高效。这是因为虚拟 DOM 的实现涉及到创建和维护虚拟 DOM 树,以及进行 diff 算法和 patching 操作,这些都需要一定的计算资源。
另外,虽然虚拟 DOM 可以高效地处理大量的 DOM 更新,但它并不能完全消除 DOM 操作的开销。当虚拟 DOM 树需要被转换为真实 DOM 时,仍然需要进行一些实际的 DOM 操作。因此,对于一些非常性能敏感的应用,比如动画或游戏,可能需要采取更为底层和优化的方法来直接操作 DOM。