vue之補充虛擬Dom(十二)

一、虛擬Dom簡介

虛擬Dom的最初出現(xiàn)是在Rect中,性能卓越

二、什么是虛擬Dom?

vdom可以看作是一個使用javascript模擬了DOM結(jié)構(gòu)的樹形結(jié)構(gòu),這個樹結(jié)構(gòu)包含整個DOM結(jié)構(gòu)的信息,如以下代碼:

//原始html結(jié)構(gòu)
<ul class="list">
      <li class="child">child1</li>
      <li class="child">child2</li>
</ul
//虛擬Dom結(jié)構(gòu)
{
   tag:"ul",
   attrs:{
       className:"list"
   },
  children:[
   {
       tag:"li",
       attrs:{
           className:"child"
       },
      children:["child1"]
  }, {
       tag:"li",
       attrs:{
           className:"child"
       },
      children:["child2"]
  }
]

}

可見上方的DOM結(jié)構(gòu),不論是標簽名稱還是標簽的屬性或標簽的子集,都會對應在下邊的樹結(jié)構(gòu)里。

三、為什么需要虛擬DOM,它有什么好處?

Web界面由DOM樹(樹的意思是數(shù)據(jù)結(jié)構(gòu))來構(gòu)建,當其中一部分發(fā)生變化時,其實就是對應某個DOM節(jié)點發(fā)生了變化,
虛擬DOM就是為了解決瀏覽器性能問題而被設計出來的。如前,若一次操作中有10次更新DOM的動作,虛擬DOM不會立即操作DOM,而是將這10次更新的diff內(nèi)容保存到本地一個JS對象中,最終將這個JS對象一次性attch到DOM樹上,再進行后續(xù)操作,避免大量無謂的計算量。所以,用JS對象模擬DOM節(jié)點的好處是,頁面的更新可以先全部反映在JS對象(虛擬DOM)上,操作內(nèi)存中的JS對象的速度顯然要更快,等更新完成后,再將最終的JS對象映射成真實的DOM,交由瀏覽器去繪制。
<1>具備跨平臺的優(yōu)勢

由于 Virtual DOM 是以 JavaScript 對象為基礎而不依賴真實平臺環(huán)境,所以使它具有了跨平臺的能力,比如說瀏覽器平臺、Weex、Node 等。

(2)操作 DOM 慢,js運行效率高。我們可以將DOM對比操作放在JS層,提高效率。

因為DOM操作的執(zhí)行速度遠不如Javascript的運算速度快,因此,把大量的DOM操作搬運到Javascript中,運用patching算法來計算出真正需要更新的節(jié)點,最大限度地減少DOM操作,從而顯著提高性能。
Virtual DOM 本質(zhì)上就是在 JS 和 DOM 之間做了一個緩存。可以類比 CPU 和硬盤,既然硬盤這么慢,我們就在它們之間加個緩存:既然 DOM 這么慢,我們就在它們 JS 和 DOM 之間加個緩存。CPU(JS)只操作內(nèi)存(Virtual DOM),最后的時候再把變更寫入硬盤(DOM)

(3)提升渲染性能
Virtual DOM的優(yōu)勢不在于單次的操作,而是在大量、頻繁的數(shù)據(jù)更新下,能夠?qū)σ晥D進行合理、高效的更新。

為了實現(xiàn)高效的DOM操作,一套高效的虛擬DOM diff算法顯得很有必要。我們通過patch 的核心----diff 算法,找出本次DOM需要更新的節(jié)點來更新,其他的不更新。比如修改某個model 100次,從1加到100,那么有了Virtual DOM的緩存之后,只會把最后一次修改patch到view上。那diff 算法的實現(xiàn)過程是怎樣的?
diff算法


image

Vue的diff算法是基于snabbdom改造過來的,僅在同級的vnode間做diff,遞歸地進行同級vnode的diff,最終實現(xiàn)整個DOM樹的更新。因為跨層級的操作是非常少的,忽略不計,這樣時間復雜度就從O(n3)變成O(n)。
diff 算法包括幾個步驟:
用 JavaScript 對象結(jié)構(gòu)表示 DOM 樹的結(jié)構(gòu);然后用這個樹構(gòu)建一個真正的 DOM 樹,插到文檔當中
當狀態(tài)變更的時候,重新構(gòu)造一棵新的對象樹。然后用新的樹和舊的樹進行比較,記錄兩棵樹差異
把所記錄的差異應用到所構(gòu)建的真正的DOM樹上,視圖就更新了

四、diff 算法的實現(xiàn)過程

diff 算法本身非常復雜,實現(xiàn)難度很大。本文去繁就簡,粗略介紹以下兩個核心函數(shù)實現(xiàn)流程:

patch(container,vnode) :初次渲染的時候,將VDOM渲染成真正的DOM然后插入到容器里面。
patch(vnode,newVnode):再次渲染的時候,將新的vnode和舊的vnode相對比,然后之間差異應用到所構(gòu)建的真正的DOM樹上。

  1. patch(container,vnode)
    通過這個函數(shù)可以讓VNode渲染成真正的DOM,我們通過以下模擬代碼,可以了解大致過程:
function createElement(vnode) {    
var tag = vnode.tag  
var attrs = vnode.attrs || {}    
var children = vnode.children || []    
if (!tag) {       
 return null  
  }    
// 創(chuàng)建真實的 DOM 元素    
var elem = document.createElement(tag)   
 // 屬性    
var attrName    
for (attrName in attrs) {    
    if (attrs.hasOwnProperty(attrName)) { 
           // 給 elem 添加屬性
           elem.setAttribute(attrName, attrs[attrName])
        }
    }
    // 子元素
    children.forEach(function (childVnode) {
        // 給 elem 添加子元素,如果還有子節(jié)點,則遞歸的生成子節(jié)點。
        elem.appendChild(createElement(childVnode))  // 遞歸
    })    // 返回真實的 DOM 元素   
 return elem
}
  1. patch(vnode,newVnode)
//考慮新舊節(jié)點對比的情況
function updateChildren(vnode, newVnode) {
    var children = vnode.children || []
    var newChildren = newVnode.children || []
  // 遍歷現(xiàn)有的children
    children.forEach(function (childVnode, index) {
        var newChildVnode = newChildren[index]
  // 兩者tag一樣
        if (childVnode.tag === newChildVnode.tag) {
            // 深層次對比,遞歸
            updateChildren(childVnode, newChildVnode)
        } else { 
  // 兩者tag不一樣
           replaceNode(childVnode, newChildVnode) 
       }
    }
)}

如果感覺有幫助,請留下一個寶貴的贊或者給小編一個贊賞?。?!

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 前言 ??Vue2.0引入了虛擬DOM,比Vue1.0的初始渲染速度提升了2~4倍,并大大降低了內(nèi)存消耗。目前主流...
    A鄭家慶閱讀 13,899評論 0 10
  • 摘要: 什么是虛擬DOM? 作者:浪里行舟 Fundebug經(jīng)授權轉(zhuǎn)載,版權歸原作者所有。 前言 Vue.js 2...
    Fundebug閱讀 7,455評論 0 6
  • 寫在前面 這篇文章算是對最近寫的一系列Vue.js源碼的文章(https://github.com/answers...
    染陌同學閱讀 2,247評論 0 14
  • 風吹過詩人的指縫雨落在流浪者的胸膛星光灑在孩子的眼瞳黑夜試圖掩蓋城市的骯臟于這無名之路 予我踽踽獨行...
    路修遠a閱讀 411評論 1 4
  • 本來以為下定決心這寫點東西的,但隔了一個星期還是什么也沒寫出來??偸且愿鞣N理由說自己沒時間,今夜是難得的獨處之夜。...
    水田wxh閱讀 216評論 0 0

友情鏈接更多精彩內(nèi)容