Vue | 虛擬DOM

一、真實DOM和其解析流程

瀏覽器渲染引擎工作流程,大致可分爲5步:

創建DOM樹——創建StyleRules——創建Render樹——佈局Layout——繪製Painting

第一步,用HTML分析器,分析HTML元素,構建一顆DOM樹(標記化和樹構建)。

第二步,用CSS分析器,分析CSS文件和元素上的inline樣式,生成頁面的樣式表。

第三步,將DOM樹和樣式表關聯起來,構建一顆Render樹(這一過程又稱爲Attachment)。
每個DOM節點都有attach方法,接受樣式信息,返回一個render對象(又名renderer)。
這些render對象最終會被構建成一顆Render樹。

第四步,有了Render樹,瀏覽器開始佈局,爲每個Render樹上的節點確定一個在顯示屏上出現的精確座標。

第五步,Render樹和節點顯示座標都有了,就調用每個節點paint方法,把它們繪製出來。

DOM樹的構建過程:

構建DOM樹是一個漸進過程,爲達到更好用戶體驗,渲染引擎會盡快將內容顯示在屏幕上。它不必等到整個HTML文檔解析完畢之後纔開始構建render數和佈局。

這三個過程在實際進行的時候又不是完全獨立,而是會有交叉。會造成一邊加載,一遍解析,一遍渲染的工作現象。

CSS的解析是從右往左逆向解析的(從DOM樹的下-上解析比上-下解析效率高),嵌套標籤越多,解析越慢。

webkit渲染引擎工作流程

二、操作真實DOM

用我們傳統的開發模式,原生JS或JQ操作DOM時,瀏覽器會從構建DOM樹開始從頭到尾執行一遍流程。

在一次操作中,我需要更新10個DOM節點,瀏覽器收到第一個DOM請求後並不知道還有9次更新操作,因此會馬上執行流程,最終執行10次。

例如,第一次計算完,緊接着下一個DOM更新請求,這個節點的座標值就變了,前一次計算爲無用功。

計算DOM節點座標值等都是白白浪費的性能。頻繁操作還是會出現頁面卡頓,影響用戶體驗

三、虛擬DOM的好處

虛擬DOM就是爲了解決瀏覽器性能問題而被設計出來的。如前,若一次操作中有10次更新DOM的動作,虛擬DOM不會立即操作DOM

而是將這10次更新的diff內容保存到本地一個JS對象中,最終將這個JS對象一次性attch到DOM樹上,再進行後續操作,避免大量無謂的計算量。

所以,用JS對象模擬DOM節點的好處是:

頁面的更新可以先全部反映在JS對象(虛擬DOM)上,操作內存中的JS對象的速度顯然要更快,等更新完成後,再將最終的JS對象映射成真實的DOM,交由瀏覽器去繪製

四、實現虛擬DOM

真是的DOM節點

真實DOM

JS來模擬DOM節點實現虛擬DOM

虛擬DOM

Element方法具體實現

Element方法具體實現

第一個參數是節點名(如div),第二個參數是節點的屬性(如class),第三個參數是子節點(如ul的li)。

除了這三個參數會被保存在對象上外,還保存了key和count。其相當於形成了虛擬DOM樹。

虛擬DOM樹

將其映射成真實DOM

虛擬DOM對象映射成真實DOM

五、diff操作

old tree

new tree

平層Diff,只有以下4種情況:

1、節點類型變了,例如下圖中的P變成了H3。我們將這個過程稱之爲REPLACE。直接將舊節點卸載並裝載新節點。這樣做效率不高。

2、節點類型一樣,僅僅屬性或屬性值變了。我們將這個過程稱之爲PROPS。此時不會觸發節點卸載和裝載,而是節點更新。

查找不同屬性方法

3、文本變了,文本對也是一個Text Node,也比較簡單,直接修改文字內容就行了,我們將這個過程稱之爲TEXT。

4、移動/增加/刪除 子節點,我們將這個過程稱之爲REORDER。看一個例子,在A、B、C、D、E五個節點的B和C中的BC兩個節點中間加入一個F節點。

我們簡單粗暴的做法是遍歷每一個新虛擬DOM的節點,與舊虛擬DOM對比相應節點對比,在舊DOM中是否存在,不同就卸載原來的按上新的。
這樣會對F後邊每一個節點進行操作。卸載C,裝載F,卸載D,裝載C,卸載E,裝載D,裝載E。效率太低。

粗暴方法

如果我們在JSX裏爲數組或枚舉型元素增加上key後,它能夠根據key,直接找到具體位置進行操作,效率比較高,可以用Levenshtein Distance算法來實現

最終Diff出來的結果

映射成真實DOM

虛擬DOM有了,Diff也有了,現在就可以將Diff應用到真實DOM上了。深度遍歷DOM將Diff的內容更新進去。

根據Diff更新DOM

根據Diff更新DOM

我們會有兩個虛擬DOM(js對象,new/old進行比較diff),用戶交互我們操作數據變化new虛擬DOM,old虛擬DOM會映射成實際DOM(js對象生成的DOM文檔)通過DOM fragment操作給瀏覽器渲染。

當修改new虛擬DOM,會把newDOM和oldDOM通過diff算法比較,得出diff結果數據表(用4種變換情況表示)。

再把diff結果表通過DOM fragment更新到瀏覽器DOM中。

注:

虛擬DOM的存在的意義:vdom 的真正意義是爲了實現跨平臺,服務端渲染,以及提供一個性能還算不錯 Dom 更新策略。vdom 讓整個 mvvm 框架靈活了起來

Diff算法:只是爲了虛擬DOM比較替換效率更高,通過Diff算法得到diff算法結果數據表(需要進行哪些操作記錄表)。

原本要操作的DOM在vue這邊還是要操作的,只不過用到了js的DOM fragment來操作dom(統一計算出所有變化後統一更新一次DOM)進行瀏覽器DOM一次性更新。

參考:https://www.jianshu.com/p/af0b398602bc

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章