一、什么是虚拟DOM?
> 1.DOM操作快不快?
DOM操作比任何第三方库都快,它只是比原生JS慢。
> 2.虚拟DOM有什么优点?
A 减少DOM操作
- 减少DOM操作的次数
- 合并DOM操作,例如要添加1000个节点,一个接一个操作肯定麻烦
- 减少DOM操作的范围
- 借助DOM diff将多余的操作省掉,例如添加1000个节点,其实只有十个是新增的
B 跨平台
- 因为虚拟DOM本质上只是一个JS对象
- 所以虚拟DOM不仅可以变成一个DOM,
- 还可以变成小程序,ios应用,安卓应用……
> 3.虚拟DOM长什么样子?
统一来说,看这个虚拟DOM表示什么DOM,子节点怎么看,事件还有标签上的属性怎么表示就知道它的结构了。
A React中的虚拟DOM结构
const VNode = {
key:null,
props:{
children:[ //子节点
{type:'span',……},
{type:'span',……},
],
className:"red", //标签上的属性
onClick:()=>{} //事件
},
ref:null,
type:'div' //标签名or属性名
……
}
B Vue中的虚拟DOM结构
const vnode = {
type: 'div',
props: { id: 'hello' },
children: [ /* 更多 vnode */ ]
}
> 4.如何得到虚拟DOM?
A React
- React.createElement
React 顶层 API – React (reactjs.org)
//React中的.js文件
createElement('div', {className='red' , onClick:()=>{}} , [
createElement('span',{},'span1'),
createElement('span',{},'span2')
])
- JSX写法
- 通过Babel转换为createElement
//React中的.jsx文件
<div className='red' onClick='{()=>{}}'>
<span>span1</span>
<span>span2</span>
</div>
B Vue
- render函数中的h()
//.vue文件
h('div',{
class:'red',
on:{click:()=>{}}
},
[h('span',{},'span1'),h('span',{},'span2')]
)
- JSX写法
- 通过vue-loader转换为h
// Vue Template .vue文件的template标签中
<div class='red' @click='fn'>
<span>span1</span>
<span>span2</span>
</div>
> 5.关于虚拟DOM的总结
Ⅰ 虚拟DOM代表什么?
一个能代表DOM树的对象,通常包含有标签名、标签上的属性、事件监听和子元素们以及其他属性
Ⅱ 虚拟DOM有什么优点?
能减少不必要的DOM操作;能跨平台渲染
Ⅲ 虚拟DOM有什么缺点?
需要额外的创建函数,例如createElement和h,但是可以通过TSX来简化成XML的写法
二、真实DOM和虚拟DOM谁更快?
当规模小的时候,虚拟DOM是非常快的;当规模非常大的时候,虚拟DOM的额外计算会消耗大量时间,而此时的真实DOM是非常快的,并且能够保持稳定性不会崩溃。
> 如何证明?
- 在JS文件中创建1000个节点,打印出运行时间
- 在React的JS文件中创建1000个节点,打印出运行时间
- 然后10倍扩大需要创建的节点数量
三、DOM diff : 虚拟DOM的对比算法
> 1.什么是DOM diff?
- Dom diff 就是一个函数,称为patch
- patch函数做的事情就是对比新旧dom得到不同的地方:
patches = patch(oldVNode,newVNode) - patches就是我们要运行的DOM操作
举两个DOM diff工作的例子,一个体现优点,一个展示缺点:
> 2.DOM diff的运行逻辑是怎么样的呢?
它可能的大概逻辑是这样的。
-
Tree diff
-
将新旧两棵树逐层对比,找出哪些节点需要更新
-
如果结点是组件就看Component diff
-
如果结点是标签就看Element diff
-
-
-
Component diff
-
如果节点是组件,就先看组件类型
-
类型不同直接替换(删除旧的)
-
类型相同则只更新属性
-
-
然后深入组件做Tree diff(递归)
-
-
Element diff
-
如果节点是原生标签,则看标签名
-
标签名不同直接替换
-
相同则只更新属性
-
-
然后进入标签后代做Tree diff(递归)
-
> 3.DOM diff的缺点
-
DOM diff的优点一早就说了,也就是可以减少DOM操作的范围,减少不必要的DOM操作
-
DOM diff的bug也在上文展示了,当你的节点没有
key的时候,同级比较会产生误会- 这也就是为什么
v-for中需要:key - 计算机做的事情就是,不管你删除哪一个,只要是一个同级同类型的标签,计算机会直接删除最后一个节点。
- 这也就是为什么
> 4.关于DOM diff的深入阅读
-
对于源码的理解,看懂热门博客,就能做到面试无忧了。
四、最后做一个重点内容的总结
> 1.虚拟 DOM 是什么
一个能代表DOM树的对象,通常包含有标签名、标签上的属性、事件监听和子元素们以及其他属性
> 2.虚拟 DOM 的优点
A 减少DOM操作
- 减少DOM操作的次数
- 合并DOM操作,例如要添加1000个节点,一个接一个操作肯定麻烦
- 减少DOM操作的范围
- 借助DOM diff将多余的操作省掉,例如添加1000个节点,其实只有十个是新增的
B 跨平台
- 因为虚拟DOM本质上只是一个JS对象
- 所以虚拟DOM不仅可以变成一个DOM,
- 还可以变成小程序,ios应用,安卓应用……
> 3.虚拟 DOM 的缺点
需要额外的创建函数,例如createElement和h,但是可以通过TSX来简化成XML的写法
> 4.DOM diff 是什么
- Dom diff 就是一个函数,称为patch
- patch函数做的事情就是对比新旧dom得到不同的地方:
patches = patch(oldVNode,newVNode) - patches就是我们要运行的DOM操作
> 5.DOM diff 的优点
也就是可以减少DOM操作的范围,减少不必要的DOM操作
> 6.DOM diff 的问题(key)
-
DOM diff的优点一早就说了,也就是可以减少DOM操作的范围,减少不必要的DOM操作
-
DOM diff的bug也在上文展示了,当你的节点没有
key的时候,同级比较会产生误会- 这也就是为什么
v-for中需要:key - 计算机做的事情就是,不管你删除哪一个,只要是一个同级同类型的标签,计算机会直接删除最后一个节点。
- 这也就是为什么