Vue中的虚拟DOM

在了解虚拟 DOM 之前,我们先看一下浏览器的渲染流程

  1. 解析获取到的 HTML 文档生成 DOM
  2. 解析 CSS 构成层叠样式表结构 CSSOM
  3. 将两者进行结合生成渲染树
  4. 浏览器根据渲染树上的节点信息确定其坐标值
  5. 调用每个节点的 paint 方法,将节点绘制到屏幕上

浏览器渲染流程

当我们使用原生 js 或者 jquery 操作 DOM 时,每对 DOM 进行一次操作,浏览器就会从头到尾执行一遍流程,当操作十分频繁时,对于浏览器的性能消耗便会变得非常严重。虚拟 DOM 就是为了解决浏览器性能问题而被设计出来的

什么是虚拟 DOM

相较于 DOM 对象,原生的 JavaScript 对象处理起来速度更快,也更简单。我们也可以用 JavaScript 对象表示出 DOM 树上的结构、属性信息,比如

COPY
1
2
3
4
5
6
7
8
9
10
11
var element = {
tagName: "ul",
props: {
id: "list",
},
children: [
{ tagName: "li", props: { class: "item" }, children: ["Item 1"] },
{ tagName: "li", props: { class: "item" }, children: ["Item 2"] },
{ tagName: "li", props: { class: "item" }, children: ["Item 3"] },
],
};

对应的 HTML 代码为

COPY
1
2
3
4
5
<ul id="list">
<li class="item">Item 1</li>
<li class="item">Item 2</li>
<li class="item">Item 3</li>
</ul>

既然 Javascript 对象属性可以用来描述 DOM 节点,那我们是不是可以通过一些操作将 Javascript 对象映射到真实 DOM 上
此时,我们边可以将虚拟 DOM 简单理解为一个 JS 对象,这个对象至少包含有标签名( tag)、属性(attrs)和子元素对象( children)三个属性。

虚拟 DOM 作用是什么

虚拟 DOM 的最终目的是将虚拟节点渲染到视图上,但如果直接覆盖的话,那虚拟 DOM 的存在也并没有什么意义了。为了避免不必要的 DOM 操作,虚拟 DOM 在将虚拟节点映射到视图的过程中,将虚拟节点与上一次渲染视图所使用的旧节点进行对比,将真正需要更新内容的节点进行映射,避免操作其他无关的 DOM

总结一下,虚拟 DOM 主要做了两件事

  1. 通过 Javascript 对象构建虚拟节点
  2. 将本次的虚拟节点与上次的进行差异对比,再进行视图更新

虚拟 Dom 的优势

「Virtual Dom 的优势」其实这道题目面试官更想听到的答案不是上来就说「直接操作/频繁操作 DOM 的性能差」,如果 DOM 操作的性能如此不堪,那么 jQuery 也不至于活到今天。所以面试官更想听到 VDOM 想解决的问题以及为什么频繁的 DOM 操作会性能差。

首先我们需要知道:

  • DOM 引擎、JS 引擎 相互独立,但又工作在同一线程(主线程)
  • JS 代码调用 DOM API 必须 挂起 JS 引擎、转换传入参数数据、激活 DOM 引擎,DOM 重绘后再转换可能有的返回值,最后激活 JS 引擎并继续执行若有频繁的 DOM API 调用,且浏览器厂商不做“批量处理”优化,
  • 引擎间切换的单位代价将迅速积累若其中有强制重绘的 DOM API 调用,重新计算布局、重新绘制图像会引起更大的性能消耗。

其次是 VDOM 和真实 DOM 的区别和优化:

  1. 虚拟 DOM 不会立马进行排版与重绘操作
  2. 虚拟 DOM 进行频繁修改,然后一次性比较并修改真实 DOM 中需要改的部分,最后在真实 DOM 中进行排版与重绘,减少过多 DOM 节点排版与重绘损耗
  3. 虚拟 DOM 有效降低大面积真实 DOM 的重绘与排版,因为最终与真实 DOM 比较差异,可以只渲染局部

写到这里,不禁有了一些疑问

作者: 果汁
文章链接: https://guozhigq.github.io/post/1e9fca9b.html
版权声明: All posts on this blog are licensed under the CC BY-NC-SA 4.0 license unless otherwise stated. Please cite 果汁来一杯 !