Virtual DOM diff算法

首先浏览器加载一个HTML页面时会经过创建DOM 树、创建样式规则(style rules)、构建渲染树(render tree)、布局layout 和 绘制页面(painting)。

传统的原生api或jQuery去操作DOM的时候,浏览器会从构建DOM树开始从头到尾执行一遍流程,所以频繁的操作DOM的代价是昂贵的。还会出现页面卡顿,影响用户的体验。

虚拟DOM就是为了解决这个问题而被设计出来,加入一次操作中有10次操作的动作,虚拟DOM不会立即执行这个操作,而是将这10次更新的diff内容

虚拟DOM是在DOM的基础上在内存建立了一个抽象层,对数据和状态所做的任何改动,都会被自动且高效的同步到虚拟DOM,最后再批量同步到DOM中

render执行的结果得到的并不是真正的DOM节点,而仅仅是javascript对象,称之为虚拟DOM

虚拟DOM具有批处理和高效的Diff算法,可以无需担心性能问题而随时‘刷新’整个页面,因为虚拟DOM能保证对界面上真正变化的部分进行实际的DOM操作

【传统DOM操作(eg:innerHtml)】:render html+重建所有DOM元素
【虚拟DOM】:render 虚拟DOM + diff算法+更新必要的DOM元素

Vue.js将DOM抽象成一个以JavaScript对象为节点的虚拟DOM树,以VNode节点模拟真实DOM,可以对这颗抽象树进行创建节点、删除节点以及修改节点等操作,在这过程中都不需要操作真实DOM,只需要操作JavaScript对象,大大提升了性能。修改以后经过diff算法得出一些需要修改的最小单位,再将这些小单位的视图进行更新。这样做减少了很多不需要的DOM操作,大大提高了性能。
 

diff的过程就是调用patch函数,就像打补丁一样修改真实dom。

function patch (oldVnode, vnode) {
    if (sameVnode(oldVnode, vnode)) {
        patchVnode(oldVnode, vnode)
    } else {
        const oEl = oldVnode.el
        let parentEle = api.parentNode(oEl)
        createEle(vnode)
        if (parentEle !== null) {
            api.insertBefore(parentEle, vnode.el, api.nextSibling(oEl))
            api.removeChild(parentEle, oldVnode.el)
            oldVnode = null
        }
    }
    return vnode
}

patch函数有两个参数,vnodeoldVnode,也就是新旧两个虚拟节点。在这之前,我们先了解完整的vnode都有什么属性,举个一个简单的例子:

// body下的 <div id="v" class="classA"><div> 对应的 oldVnode 就是

{
  el:  div  //对真实的节点的引用,本例中就是document.querySelector('#id.classA')
  tagName: 'DIV',   //节点的标签
  sel: 'div#v.classA'  //节点的选择器
  data: null,       // 一个存储节点属性的对象,对应节点的el[prop]属性,例如onclick , style
  children: [], //存储子节点的数组,每个子节点也是vnode结构
  text: null,    //如果是文本节点,对应文本节点的textContent,否则为null
}

需要注意的是,el属性引用的是此 virtual dom对应的真实dom,patchvnode参数的el最初是null,因为patch之前它还没有对应的真实dom。

发布了81 篇原创文章 · 获赞 62 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_38021852/article/details/88309792
今日推荐