什么是Virtual DOM?
Virtual DOM是对DOM的抽象,本质上是JavaScript对象(也就是通过JavaScript语言来描述一段HTML代码),这个对象就是更加轻量级的对DOM的描述.
虚拟DOM首次产生是React框架最先提出和使用的,其卓越的性能很快得到广大开发者的认可,继React之后vue2.0也在其核心引入了虚拟DOM的概念。在没有虚拟DOM的时候,我们在创建页面的时候一般都是使用HTML标签一个一个的去搭建我们的页面,既然有了DOM节点以后,为什么不直接使用原生DOM,那么原生DOM到底有什么弊端呢?原因是这个样子的,原生DOM中一个Node节点有N多的属性,一旦对DOM进行操作的时候会影响页面性能的核心问题主要在于DOM操作导致了页面的重绘或重排,为了减少由于重绘和重排对网页性能的影响,所以无论在什么项目中尽可能少的去操作DOM节点是性能优化的一大重点。
为什么需要DOM?
既然我们已经有了DOM,为什么还需要额外加一层抽象?
- 1. 首先,前端性能优化的一个秘诀就是尽可能少地操作DOM,DOM相对较慢,而且频繁变动DOM会造成浏览器的回流或者重绘,这些都是性能的杀手,因此我们需要这一层抽象,在patch过程中尽可能地一次性将差异更新到DOM中,这样保证了DOM不会出现性能很差的情况。
- 2. 其次,现代前端框架的一个基本要求就是无须手动操作DOM,不仅因为手动操作DOM无法保证程序性能,多人协作的项目中如果review不严格,可能会有开发者写出性能较低的代码,而且省略手动DOM操作可以大大提高开发效率。
- 3. 最后,Virtual DOM最初的目的就是更好的跨平台,比如Node.js就没有DOM,如果想实现SSR(服务端渲染),那么可以借助Virtual DOM,因为Virtual DOM本身是JavaScript对象。
Virtual DOM的关键要素
HTML:
<div class="" id="app">
<p class="text">节点一</p>
</div>
Javascript
const createElement = () => {
return {
"tag":"div",
"prop":{
"id":"app"
},
"children":[
{
"tag":"p",
"prop":{
"class":"text"
},
"children":["节点一"]
}
]
}
}
上面的代码中,只是简单的使用了JavaScript语言简单描述了一下HTML部分相对应的代码,此时我们只需要再写入一个创建DOM的方法,按照文档描述将创建好的DOM按照层级添加到里面页面中就好了。
上述JavaScript中所描述的数据类型也就可以简单的理解为是虚拟DOM,虽然这个虚拟DOM是那么的简陋,但是足可以说明情况啦,像Vue和React当需要对页面进行渲染更新的时候,则对比的就是虚拟DOM更新前后的差异,只对有差异的部分进行更新,大大减少了对DOM的操作。也就是我们经常所说的DIFF算法
。
通过上述描述可以总结得出,由于原生DOM节点中的属性和方法过于复杂,操作时过于影响性能,所以使用Object来描述页面中的HTML结构,以达到对性能的提升。
在明确了我们抽象的Virtual DOM构造之后,我们就需要一个函数来创建Virtual DOM.
/**
* 生成 vnode
* @param {String} type 类型,如 'div'
* @param {String} key key vnode的唯一id
* @param {Object} data data,包括属性,事件等等
* @param {Array} children 子 vnode
* @param {String} text 文本
* @param {Element} elm 对应的 dom
* @return {Object} vnode
*/
function vnode(type, key, data, children, text, elm) {
const element = {
__type: VNODE_TYPE,
type, key, data, children, text, elm
}
return element
}
参考:
https://segmentfault.com/a/1190000019992100
https://juejin.im/post/5d3f3bf36fb9a06af824b3e2