【1113 | Day60】靈魂拷問:什麼是虛擬DOM?

什麼是虛擬DOM?

1、前言

虛擬DOM概念隨着react的誕生而誕生,由facebook提出,其卓越的性能很快獲得廣大開發者的承認;繼react以後vue2.0也在其核心引入了虛擬DOM的概念,本文將以vue2.0使用的snabbdom入手,來介紹虛擬DOM的主要實現原理。前端

2、虛擬DOM

在開始介紹snabbdom以前咱們想來想兩個問題,vue

(1)什麼是虛擬DOM?

vdom能夠看做是一個使用javascript模擬了DOM結構的樹形結構,這個樹結構包含整個DOM結構的信息,以下圖:java

img img

可見左邊的DOM結構,不管是標籤名稱仍是標籤的屬性或標籤的子集,都會對應在右邊的樹結構裏。node

(2)爲何要使用虛擬DOM?

以前使用原生js或者jquery寫頁面的時候會發現操做DOM是一件很是麻煩的一件事情,每每是DOM標籤和js邏輯同時寫在js文件裏,數據交互時不時還要寫不少的input隱藏域,若是沒有好的代碼規範的話會顯得代碼很是冗餘混亂,耦合性高而且難以維護。react

另一方面在瀏覽器裏一遍又一遍的渲染DOM是很是很是消耗性能的,經常會出現頁面卡死的狀況;因此儘可能減小對DOM的操做成爲了優化前端性能的必要手段,vdom就是將DOM的對比放在了js層,經過對比不一樣之處來選擇新渲染DOM節點,從而提升渲染效率。jquery

(3)vdom如何使用?

下面我將使用snabbdom的用法介紹一下vdom的使用。git

3、snabbdom

要了解snabbdom的話有必要先去github上先了解下snabbdom: https://github.com/snabbdom/snabbdomgithub

在這裏看到官方給的一個example算法

img

這裏能夠看到列出來的兩個主要的核心函數,即h()函數和patch()函數,咱們先來看下h()函數:

h函數

img img

能夠看到建立的虛擬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進行深度對比。

4、小結

虛擬DOM在目前流行的幾大框架中都做爲核心的一部分使用,可見其性能的高效,本文只是簡單的經過列舉vue中使用的snabbdom庫作一個簡單的剖析,想要更深層次的理解vdom還有很長的路要走,本文若有不當之處,還勞煩路過大佬批評指出。

相關文章
相關標籤/搜索