一、何为虚拟DOM
解释1:用js模拟一颗DOM树,放在浏览器的内存中,当需要变更时,虚拟DOM进行diff算法进行新旧虚拟DOM的对比,将变更放入到队列中。反应到实际的DOM上,减少DOM的操作。
解释2:虚拟DOM将DOM转换为一颗js树。diff算法逐级的进行比较、删除、新增操作。但是如果存在多个相同的元素可能比浪费性能,所以React和Vue引用key值进行区分。
二、为什么DOM渲染慢?
所谓DOM渲染,即浏览器将HTML字符串转换成网页视图并渲染视图的过程。
- 首先,浏览器的HTML解析器,会对HTML字符串进行解析,并将它转换成DOM树,同时,CSS解析器也会解析HTML使用到的CSS样式,生成一系列CSS规则。
- 然后浏览器的渲染引擎将DOM树和CSS规则进行整合,并生成一个可用于视图渲染的DOM渲染树。
- 接着确定DOM布局,即每一个节点在浏览器中的确切位置。
- 最后一步是进行绘制,将每一个节点的每一个像素都绘制在屏幕上。
为了理解这一过程的复杂性,我们可以对HTML解析器的处理做一个特写:在HTML解析器中,有两个程序交替执行:分词程序和解析程序;分词程序负责将HTML字符串划分成合法的DOM标签字符串,然后将它们交给用于处理的解析器,解析器将它们添加到正在构建的DOM树中;当分词器解析所有字符串时,将构建DOM树。
您可以理解为什么DOM呈现如此缓慢:这个过程真的太复杂了。在web页面交互中添加和删除DOM将大大降低视图呈现和交互的效率。
三、为什么我们要使用虚拟DOM?
- 保证性能下限
- 不需要手动优化的情况下,我依然可以给你提供过得去的性能
- 跨平台
四、保证性能下线
框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;
例如比较 innerHTML vs. Virtual DOM 的重绘性能消耗:
- innerHTML: render html string O(template size) + 重新创建所有 DOM 元素 O(DOM size)
- Virtual DOM: render Virtual DOM + diff O(template size) + 必要的 DOM 更新 O(DOM change)
Virtual DOM render + diff 显然比渲染 html 字符串要慢,但是!它依然是纯 js 层面的计算,比起后面的 DOM 操作来说,依然便宜了太多。
可以看到,innerHTML 的总计算量不管是 js 计算还是 DOM 操作都是和整个界面的大小相关,但 Virtual DOM 的计算量里面,只有 js 计算和界面大小相关,DOM 操作是和数据的变动量相关的。
前面说了,和 DOM 操作比起来,js 计算是极其便宜的。这才是为什么要有 Virtual DOM:它保证了不管你的数据变化多少,每次重绘的性能都可以接受。保证了性能的下线。
五、不需要手动优化的情况下,我依然可以给你提供过得去的性能
这里直接看看尤大大在知乎的一个解释。
六、跨平台
虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。