目录javascript
虚拟DOM概念随着react的诞生而诞生,由facebook提出,其卓越的性能很快获得广大开发者的承认;继react以后vue2.0也在其核心引入了虚拟DOM的概念,本文将以vue2.0使用的snabbdom入手,来介绍虚拟DOM的主要实现原理。前端
在开始介绍snabbdom以前咱们想来想两个问题,vue
vdom能够看做是一个使用javascript模拟了DOM结构的树形结构,这个树结构包含整个DOM结构的信息,以下图:java
可见左边的DOM结构,不管是标签名称仍是标签的属性或标签的子集,都会对应在右边的树结构里。node
以前使用原生js或者jquery写页面的时候会发现操做DOM是一件很是麻烦的一件事情,每每是DOM标签和js逻辑同时写在js文件里,数据交互时不时还要写不少的input隐藏域,若是没有好的代码规范的话会显得代码很是冗余混乱,耦合性高而且难以维护。react
另一方面在浏览器里一遍又一遍的渲染DOM是很是很是消耗性能的,经常会出现页面卡死的状况;因此尽可能减小对DOM的操做成为了优化前端性能的必要手段,vdom就是将DOM的对比放在了js层,经过对比不一样之处来选择新渲染DOM节点,从而提升渲染效率。jquery
下面我将使用snabbdom的用法介绍一下vdom的使用。git
要了解snabbdom的话有必要先去github上先了解下snabbdom: https://github.com/snabbdom/snabbdomgithub
在这里看到官方给的一个example算法
这里能够看到列出来的两个主要的核心函数,即h()函数和patch()函数,咱们先来看下h()函数:
h函数
能够看到建立的虚拟DOM树里面的结构在左边的vnode里都有体现,因此如今看来咱们的虚拟DOM结构树和snabbdom中的h()函数是彻底能够对应起来的,能够经过一个方法将虚拟DOM结构转化成vnode;而上图中newVnode则指的是虚拟DOM树中的数据发生变化以后生成的vnode。
咱们在回过头来看patch()函数
patch函数
patch函数的执行分为两个阶段,两次传递的参数都是两个
第一阶段为虚拟dom的第一次渲染,传递的两个参数分别是放真实DOM的container和生成的vnode,此时patch函数的做用是用来将初次生成的真实DOM结构挂载到指定的container上面。
第二阶段传递的两个参数分别为vnode和newVnode,此时patch函数的做用是使用diff算法对比两个参数的差别,进而更新参数变化的DOM节点;
能够发发现h函数和patch函数在cnabbdom中实现vdom到真实DOM的转化起到了相当重要的做用,那么还有一个很重要的环节,patch函数中是怎么样实现对比两个vnode从而实现对真实DOM的更新的呢,这里还要提一下snabbdom的另一个核心算法,即diff算法。
diff算法
其实在咱们平常开发中咱们都在接触相似与diff算法的一些软件,好比svn能够看到当前代码和svn服务器上代码的不一样之处,再如Beyond Compare这款软件也能够为咱们指出两个对比文件的不一样之处
可是此处是如何实现对vnode的对比的呢?参考如下代码:
1 function updateChildren(vnode, newVnode) { // 建立对比函数 2 var children = vnode.children || [] 3 var newChildren = newVnode.children || [] 4 5 children.forEach(function(childrenVnode, index) { 6 var newChildVnode = newChildren[index] // 首先拿到对应新的节点 7 if (childrenVnode.tag === newChildVnode.tag) { // 判断节点是否相同 8 updateChilren(childrenVnode, newChildVnode) // 若是相同执行递归,深度对比节点 9 } else { 10 repleaseNode(childrenVnode, newChildVnode) // 若是不一样则将旧的节点替换成新的节点 11 } 12 }) 13 } 14 15 16 function repleaseNode(vnode, newVnode) { // 节点替换函数 17 var elem = vnode.elem 18 var newEle = createElement(newVnode) 19 }
此处简单的列举了一下diff算法的原理,以上是最简单的对比,更复杂的对比函数包括对节点的增删以及其它的节点逻辑就不一一赘述了,这里最重要的一部分就是递归的使用,才能将vnode进行深度对比。
虚拟DOM在目前流行的几大框架中都做为核心的一部分使用,可见其性能的高效,本文只是简单的经过列举vue中使用的snabbdom库作一个简单的剖析,想要更深层次的理解vdom还有很长的路要走,本文若有不当之处,还劳烦路过大佬批评指出。