一 虚拟DOM是什么
- 虚拟DOM是相对于真实DOM而言的,一个能代表DOM树的js对象,通常含有标签名,标签上的属性,事件监听和子元素们,以及其他属性。
二 虚拟DOM的优点
- 能减少DOM操作
(1) 能减少DOM操作的次数
比如向页面中添加1000个div,js会一个一个的添加,操作1000次,而虚拟DOM可以将多次操作合并为一次操作。
(2) 能减少DOM操作的范围
虚拟DOM借助DOM diff可以把多余的操作省掉,比如页面中添加1000个节点,其中只有10个是新增的。通过对比区分新旧节点,如果发现有些节点已经在页面了,不需要更新,他就不更新了,减少DOM操作的范围。 - 能跨平台渲染
因为虚拟DOM本质上是一个js对象,他可以变成DOM树,也可以变成ios上的树,安卓上的树。
三 虚拟DOM的缺点
- 需要用额外的创建函数来创建DOM,如createElement或h。
- 可以简化,React使用JSX语法,Vue使用模板语法。但是这种简化写法严重依赖于打包工具,需要额外的构建过程。如果不打包的话,js是不认识的。
<div className="red" onClick={fn}>
<span>span1</span>
<span>span2</span>
</div>
//通过babel转为createElement形式
<div class="red" @click="fn">
<span>span1</span>
<span>span2</span>
</div>
//通过vue-loader转为h形式
四 DOM操作慢?虚拟DOM快?
- DOM操作慢是相对于JS原生API来讲的,比如数组操作。因为DOM操作需要跨线程通信,所以相对慢。
- 任何基于DOM的库(vue/react)都不可能在操作DOM时比DOM快
- 只能说在某些情况下,虚拟DOM快,比如上面所讲虚拟DOM的优点
五 DOM diff
给定任意两棵树,采用先序深度优先遍历的算法找到最少的转换步骤。简单来讲就是对比新旧虚拟DOM这两个对象差异,创建出补丁,描述改变的内容,将这个补丁用来更新DOM。主要过程包括
- tree diff
(1) 将新旧两棵树逐层对比,找出哪些节点需要更新
(2) 如果节点是组件就看 Component diff
(3) 如果节点是标签就看 Element diff - component diff
(1) 如果节点是组件,就先看组件类型
(2) 类型不同直接替换(删除旧的)
(3) 类型相同则只更新属性
(4) 然后深入组件做 Tree diff(递归) - element diff
(1) 如果节点是原生标签,则看标签名
(2) 标签名不同直接替换,相同则只更新属性
(3) 然后进入标签后代做 Tree diff(递归)
六 DOM diff的优点
通过对比新旧虚拟DOM这两个对象的差异(Diff算法),最终只把变化的部分重新渲染,提高渲染效率的过程。
七 DOM diff的缺点
同级节点对比存在 bug,比如Vue中,v-for使用时必须添加唯一的可以标识节点的key。