1. 程式人生 > 程式設計 >vue 虛擬DOM的原理

vue 虛擬DOM的原理

為什麼需要虛擬DOM?

  如果對前端工作進行抽象的話,主要就是維護狀態和更新檢視,而更新檢視和維護狀態都需要DOM操作。其實近年來,前端的框架主要發展方向就是解放DOM操作的複雜性。

  執行js的速度是很快的,大量的操作DOM就會很慢,時常在更新資料後會重新渲染頁面,這樣造成在沒有改變資料的地方也重新渲染了DOM 節點,這樣就造成了很大程度上的資源浪費。

  在jQuery出現以前,我們直接操作DOM結構,這種方法複雜度高,相容性也較差。有了jQuery強大的選擇器以及高度封裝的API,我們可以更方便的操作DOM,jQuery幫我們處理相容性問題,同時也使DOM操作變得簡單。

  但是聰明的程式設計師不可能滿足於此,各種MVVM框架應運而生,有angularJS、avalon、vue.js等,MVVM使用資料雙向繫結,使得我們完全不需要操作DOM了,更新了狀態,檢視會自動更新。更新了檢視資料狀態也會自動更新,可以說MVVM使得前端的開發效率大幅提升。但是其大量的事件繫結使得其在複雜場景下的執行效能堪憂,有沒有一種兼顧開發效率和執行效率的方案呢?由此引入Virtual DOM(虛擬DOM)。

  利用在記憶體中生成與真實DOM與之對應的資料結構,這個在記憶體中生成的結構稱之為虛擬DOM 。

  當資料發生變化時,能夠智慧地計算出重新渲染元件的最小代價並應用到DOM操作上。

Virtual DOM 演算法

  所謂的 Virtual DOM 演算法。包括幾個步驟:

  1.用 JavaScript 物件結構表示 DOM 樹的結構;然後用這個樹構建一個真正的 DOM 樹,插到文件當中;

  2.當狀態變更的時候,重新構造一棵新的物件樹。然後用新的樹和舊的樹進行比較,記錄兩棵樹差異;

  3.把2所記錄的差異應用到步驟1所構建的真正的DOM樹上,檢視就更新了。

  Virtual DOM 本質上就是在 JS 和 DOM 之間做了一個快取。可以類比 CPU 和硬碟,既然硬碟這麼慢,我們就在它們之間加個快取。

  既然 DOM 這麼慢,我們就在它們 JS 和 DOM 之間加個快取。CPU(JS)只操作記憶體(Virtual DOM),最後的時候再把變更寫入硬碟(DOM)。

  所謂的virtual dom,也就是虛擬節點。它通過js的Object物件模擬DOM中的節點,然後再通過特定的render方法將其渲染成真實的DOM節點 dom。diff 則是通過JS層面的計算,返回一個patch物件,即補丁物件,在通過特定的操作解析patch物件,完成頁面的重新渲染。

vue 虛擬DOM的原理

比較兩棵虛擬DOM樹的差異

  比較兩棵DOM樹的差異是 Virtual DOM 演算法最核心的部分,這也是所謂的 Virtual DOM 的 diff 演算法。

  兩個樹的完全的 diff 演算法是一個時間複雜度為 O(n^3) 的問題。但是在前端當中,你很少會跨越層級地移動DOM元素。所以 Virtual DOM 只會對同一個層級的元素進行對比:

vue 虛擬DOM的原理

  上面的div只會和同一層級的div對比,第二層級的只會跟第二層級對比。這樣演算法複雜度就可以達到 O(n)。

  在實際的程式碼中,會對新舊兩棵樹進行一個深度優先的遍歷,這樣每個節點都會有一個唯一的標記,如下圖所示:

vue 虛擬DOM的原理

Virtual DOM 演算法實現

  Virtual DOM 演算法得實現主要是用三個函式:element,diff,patch。然後就可以實際的進行使用,如下面程式碼所示:

// 1. 構建虛擬DOM
var tree = el('div',{'id': 'container'},[
  el('h1',{style: 'color: blue'},['simple virtal dom']),el('p',['Hello,virtual-dom']),el('ul',[el('li')])
])

// 2. 通過虛擬DOM構建真正的DOM
var root = tree.render()
document.body.appendChild(root)

// 3. 生成新的虛擬DOM
var newTree = el('div',{style: 'color: red'},[el('li'),el('li')])
])

// 4. 比較兩棵虛擬DOM樹的不同
var patches = diff(tree,newTree)

// 5. 在真正的DOM元素上應用變更
patch(root,patches)

diff演算法

用 三大策略 將O(n^3)複雜度 轉化為 O(n)複雜度

  • 策略一(tree diff):

  Web UI中DOM節點跨層級的移動操作特別少,可以忽略不計。

  • 策略二(component diff):

  擁有相同類的兩個元件 生成相似的樹形結構,
  擁有不同類的兩個元件 生成不同的樹形結構。

  • 策略三(element diff):

  對於同一層級的一組子節點,通過唯一id區分。

tree diff

(1)通過updateDepth對Virtual DOM樹進行層級控制。
(2)對樹分層比較,兩棵樹只對同一層次節點進行比較。如果該節點不存在時,則該節點及其子節點會被完全刪除,不會再進一步比較。
(3)只需遍歷一次,就能完成整棵DOM樹的比較。

vue 虛擬DOM的原理

  diff只簡單考慮同層級的節點位置變換,如果是跨層級的話,只有建立節點和刪除節點的操作。

vue 虛擬DOM的原理

如上圖所示,以A為根節點的整棵樹會被重新建立,而不是移動,因此官方建議不要進行DOM節點跨層級操作,可以通過CSS隱藏、顯示節點,而不是真正地移除、新增DOM節點。

以上就是vue 虛擬DOM的原理的詳細內容,更多關於vue 虛擬DOM的資料請關注我們其它相關文章!