本文已参与「新人创作礼」活动,一起开启掘金创作之路。
vue深入系列包括以下内容,有兴趣的读者可以选择阅读:
【Vue深入】之DIFF算法 - 掘金 (juejin.cn)
【Vue深入】之路由router - 掘金 (juejin.cn)
【Vue深入】之响应式原理 - 掘金 (juejin.cn)
【Vue深入】之Vuex状态管理 - 掘金 (juejin.cn)
引言
现如今Vue已成为当下主流框架,其中一些核心概念更是面试须知,本文主要进行对Virtual DOM
的一些原理分析,希望能够对大家有所帮助。
在 Vue.js
中,Virtual DOM
是用 VNode
这个 Class
去描述,它定义在 src/core/vdom/vnode.js
中。实际上 Vue.js
中 Virtual DOM
是借鉴了开源库 snabbdom 的实现,然后加入了一些 Vue.js
自己的一些特性。
1、真实DOM
在开始虚拟DOM之前,我们先要了解真实 DOM
的解析过程,通过介绍其解析过程以及存在的问题,从而引出为什么需要虚拟DOM
。
浏览器渲染引擎工作流程大致分为以下四步:创建DOM树 -> 生成Style Rules -> 生成render树 -> 布局render树 -> 绘制render树
-
创建DOM树:渲染引擎首先解析HTML文档,生成DOM树。 用CSS分析器,分析CSS文件和元素上的inline样式,生成页面的样式表。
-
生成样式表:用CSS分析器,分析CSS文件和元素上的inline样式,生成页面的样式表。
-
生成render树:将DOM树和样式表,关联起来,构建一颗Render(渲染)树。
-
布局render树:有了Render树,浏览器开始对渲染树的每个节点进行布局处理,确定其在屏幕上的显示位置。
-
绘制render树:遍历渲染树,然后调用每个节点的 paint 方法,将它们绘制出来。
2.虚拟DOM
什么是虚拟DOM
虚拟DOM(Virtual Dom),也就是我们常说的虚拟节点,是用JS对象来模拟真实DOM中的节点,该对象包含了真实DOM的结构及其属性,用于对比虚拟DOM和真实DOM的差异,从而进行局部渲染来达到优化性能的目的。
为什么使用虚拟DOM
起初我们在使用JS进行DOM操作的的时候,DOM的变化会引发回流或重绘,从而降低页面渲染性能。所以虚拟DOM出现的主要目的就是为了减少频繁操作DOM而引起回流重绘所引发的性能问题。
虚拟DOM的作用
- 兼容性好。因为Vnode本质是JS对象,所以不管Node还是浏览器环境,都可以操作;
- 减少了对Dom的操作。页面中的数据和状态变化,都通过Vnode对比,只需要在比对完之后更新DOM,不需要频繁操作,提高了页面性能;
真实节点如何转化为虚拟DOM
在一个组件实例第一次被渲染的时候,它会先生成虚拟DOM树,然后根据虚拟DOM树创建真实DOM,最后会把真实的DOM挂载到页面中合适的位置。
如果说页面只需要渲染一次,后面的数据变化都不重新渲染页面,这时vue的效率跟直接操作DOM效率相比其实是更加低的,因为它比直接操作DOM还多一个步骤:创建虚拟DOM。所以说,页面初始化的时候创建真实的DOM这一步是少不了的,也就是大家常说的页面初始化的时候vue渲染效率是不高的。
但是当一个组件受到响应式数据变化的影响,需要重新渲染的时候,它便会重新调用render函数,创建一个新的虚拟DOM树,然后会使用新虚拟DOM树(newVnode)和旧虚拟dom树(oldVnode)进行对比,通过比对,vue会找到最小更新量,然后更新必要的虚拟DOM节点,最后,这些更新过的虚拟节点会去修改它们对应的真实DOM。这样一来就保证了对真实DOM的操作达到了最小的改动。
真实DOM
:
<ul id="list">
<li class="item1">测试1</li>
<li class="item2">测试2</li>
<li class="item3">测试3</li>
</ul>
对应的虚拟DOM
:
let oldVDOM = {
// 标签名
tagName: 'ul',
// 标签属性
props: {
id: 'list'
},
// 标签子节点
children: [
{
tagName: 'li', props: { class: 'item1' }, children: ['测试1']
},
{
tagName: 'li', props: { class: 'item2' }, children: ['测试2']
},
{
tagName: 'li', props: { class: 'item3' }, children: ['测试3']
},
]
}
3.虚拟DOM和真实DOM的区别
- 虚拟DOM不会进行回流和重绘;
- 真实DOM在频繁操作时引发的回流重绘导致性能很低;
- 虚拟DOM频繁修改,然后一次性对比差异并修改真实DOM,最后进行依次回流重绘,减少了真实DOM中多次回流重绘引起的性能损耗;
- 虚拟DOM有效降低大面积的重绘与排版,因为是和真实DOM对比,更新差异部分,所以只渲染局部;
计算使用真实DOM的损耗 总损耗 = 真实DOM增删改 + (多节点)回流/重绘;
计算使用虚拟DOM的损耗 总损耗 = 虚拟DOM增删改 + (diff对比)真实DOM差异化增删改 + (较少节点)回流/重绘;
可以发现,虚拟DOM对比真实DOM来说,减少了重绘和回流的次数,从而达到了减少性能消耗的目的。
结语
本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力。