操作虚拟
dom
比直接操作真实dom
要快,这似乎已经刻在了大家的脑子里,但实际上不是这样的。
想要更严谨的回答的话,只能说:虚拟dom
并不是比原生dom
要快,更确切的说,虚拟dom
是比操作不当的原生dom
快
虚拟dom的真面目
//虚拟DOM的真身
const vNode = {
key:"d", //是否有key,有则显示,无则显示null
props:{
//标签里是否子元素
children:[
{
....,
ref:"null",
type:'p'},
],
onClick:() => {}, //标签上的事件
className:"d-class", //标签上的属性
}
ref:"null",
type:"div"
}
使用真实dom映射后:
<div className="root" key="rootKey" ref="rootRef">
<h1>我是H1</h1>
<div className="top" onClick={() => console.log(".......)}>
<p>我是段落</p>
</div>
</div>
与之对应的虚拟dom:
const VNode = {
//第一层的div节点
key:"rootKey",
props:{
className:"root"
},
//第二层的h1和div节点
children:[
//h1
{
children:"我是H1",
type:"h1",
props:{}
},
//div
{
type:"div",
props:{
className:"top",
onClick:() => console.log("............")
},
//div下的p标签
children:[
{
type:"p",
children:"我是段落"
}
]
}
],
ref:"rootRef",
type:"div"
}
所谓的虚拟
dom
,就是我们真实dom
在创建的时候,隐藏在真实dom
之下和真实dom
所对应的一个对象。这个对象,被我们称为虚拟dom
虚拟dom为什么存在
最开始的核心是为了提升开发效率,而非性能提升。
-
我们使用
react、vue
之后,我们只需要关注数据的改变,至于dom
的一系列动作,在我们的数据改变之后,react、vue
会为我们代劳,这极大程度的提升了我们的开发效率,也是react、vue
的核心思想和初衷。 -
至于很多人说虚拟
dom
操作会比原生dom
更快,也不全面。比如,首次渲染或者所有节点都需要进行更新的时候,这个时候采用虚拟dom
会比直接操作原生dom
多一重构建虚拟dom
的动作,会占用更多的内存以及延长渲染时间。
举个例子🌰
首次渲染不采用虚拟dom:
- 浏览器接受绘制指令
- 创建所有节点
首次渲染采用虚拟dom:
- 浏览器接受绘制指令
- 创建虚拟dom
- 创建所有节点
⚠️注意:虚拟dom的存在,并不是免费的,对比新旧虚拟dom树的差异会带来一定的性能开销。
虚拟dom
的优势在于我们更新节点的时候,它会检查哪些节点需要更新。尽量复用已有dom
,减少dom
的删除和创建。并且这些操作我们是可以通过手动操作js
底层api
实现的。只是我们手动操作会比较费时,这个工作由虚拟dom
代劳会让我们开发更快速便捷。
举个例子🌰
- 在采用虚拟
dom
时,假设我们有节点A
,两个子节点B/C
。然后我们删除C
,这个时候会有两棵虚拟dom
树,一棵是修改前的A->B/C
,另一个棵是修改后的A->B/C
diff
算法会对比这两棵树的差异,然后发现A->B
没有更改,保留A->B
,C
被删除了,那么A->B
两个节点的删除和创建操作就省略了,拿来即用。
- 如果不采用虚拟
dom
的话,使用JQ
的模版,我们可能会把A->B/C
三个节点全部删除,再全部重新创建,而A->B
是没有改动的,它们的创建删除是完全不必要的开销,我们使用框架做出的一切行为,都会被框架转化为对原生dom
的操作。
总结
- 虚拟
DOM
不一定会比操作原生DOM
更快。 - 虚拟
DOM
的优势在于节点进行改动的时候尽量减少开销