一、什么是虛擬dom?
虛擬dom 其實就是一個普通的JavaScript對象,用來描敘試圖上有哪些界面結構,並不生成界面,我們可以在生命周期【mounted階段】打印this._vnode,如下:
它描敘了該階段是div,有 哪些子節點,哪些屬性,它是采用一個js對象來描敘這些,但是它並不會顯示在頁面上。
在vue中,每一個組件都有一個render函數,這個函數會生成一個虛擬dom,這就意味着每一個組件都對應一個虛擬dom樹。
二、為什么需要虛擬dom?
這個主要是由vue結構所決定的,在vue中,渲染試圖會調用render函數,不僅在創建視圖的時候被調用,當組件所依賴的數據或者屬性發生了改變的時候,也會調用render函數,如果是使用真實的dom,當創建,修改,刪除,插入dom的話是非常消耗性能的,如下所示,當修改一個js對象遠比操作真實的dom要有效率的多。
<script> var times = 10000000;//次數為1000萬次 //js對象 console.time(`js object`); for (var i = 0; i < times; i++) { var obj = {}; } console.timeEnd("js object"); //真實dom對象 console.time(`dom object`); for (var i = 0; i < times; i++) { var obj = document.createElement("div"); } console.timeEnd("dom object"); </script> 「運行結果」:
運行結果:
三、虛擬dom是如何轉換為真實dom的?
在組件渲染的時候會調用render函數,這個函數會生成一個虛擬的dom,再根據這個虛擬的dom來生成真實的dom,然后將這個真實的dom給掛載到頁面的合適的部位,總的來說創建真實的dom是必不可少的一部分,如果視圖只需要渲染一次,后續數據的改變不會影響到視圖的改變,vue的效率其實要比真實操作dom的效率要低,因為vue還要創建一個虛擬的dom,但是如果組件內有響應式的數據,當數據發生改變的時候,就會調用render 函數來生成一個新的虛擬dom樹,將新的虛擬dom樹和舊的虛擬dom樹進行對比,然后找到必須修改的虛擬dom,最后根據修改的虛擬dom,來修改真實的dom,這樣就保證了對真實的dom操作達到最小的改變,
在進行新的虛擬dom和舊的虛擬dom對比的算法是patch算法,它會找到新的虛擬dom樹和舊的虛擬dom樹之間的差別。
四、模板和虛擬dom的關系?
在vue中有一個compile模塊,這個模塊將template字符串編譯成render函數,render函數最后返回一個虛擬dom。
編譯過程分為兩步:
(1)將template 轉換為AST(抽象語法樹)
(2)將AST轉換為render函數
* 使用<script>標簽來引入vue 的,編譯是發生在組件第一次加載的時候,這種稱為 運行時編譯
* 第二種是使用 vue-cil 框架生成的 vue 項目,這種是在打包的時候就進行了編譯,稱為 模板預編譯
編譯
是一個極其耗費性能的操作,預編譯可以有效的提高運行時的性能,而且,由於運行時已經不需要編譯,vue-cli在打包時會排除掉vue中的compile模塊,這樣可以減少打包體積。
模板的存在,僅僅只是為了我們更加方便的書寫界面代碼,vue最終運行的時候,最終需要的是render函數,而不是模板,這里要注意的是vue它是不認識模板的,模板是vue-cli預編譯所需要的,它最終會將模板編譯成render函數提供給vue正常運行。因此模板中的各種語法,在虛擬dom中都是不存在的,它們都會變成虛擬dom的配置。
轉自:https://mp.weixin.qq.com/s/g7wQXjXeFNxtLzGS1uM6uA