vue 渲染原理

如今基本全部的框架都已經認同這個見解——DOM應儘量是一個函數式到狀態的映射。狀態便是惟一的真相,而DOM狀態只是數據狀態的一個映射。以下圖所示,全部的邏輯儘量在狀態的層面去進行,當狀態改變的時候,View應該是在框架幫助下自動更新到合理的狀態,而不是說當你觀測到數據變化以後手動選擇一個元素,再命令式地去改動它的屬性。數組

 

下圖是Vue的一個模板示例,若是沒有用過Vue的話,能夠大概感受到這是一個怎樣的概念。瀏覽器

 

其實,在模板語法上,Vue跟Angular是比較類似。在Vue1.0裏面,模板實現跟Angular相似,以下圖所示,把模板直接作成在瀏覽器裏面parse成DOM樹,而後去遍歷這個樹,提取其中的各類綁定。架構

 

在Vue2.0中,渲染層的實現作了根本性改動,那就是引入了虛擬DOM。框架

 

從架構來說,Vue2.0 依然是寫同樣的模板,(Vue2.0於前段時間發佈,具體報道:更輕更快的Vue.js 2.0)。在最左邊,Vue2.0跟1.0的模板語法絕大部分是兼容的。Vue的編譯器在編譯模板以後,會把這些模板編譯成一個渲染函數。而函數被調用的時候就會渲染而且返回一個虛擬DOM的樹。這個樹很是輕量,它的職責就是描述當前界面所應處的狀態。當咱們有了這個虛擬的樹以後,再交給一個patch函數,負責把這些虛擬DOM真正施加到真實的DOM上。在這個過程當中,Vue有自身的響應式系統來偵測在渲染過程當中所依賴到的數據來源。在渲染過程當中,偵測到的數據來源以後,以後就能夠精確感知數據源的變更。到時候就能夠根據須要從新進行渲染。當從新進行渲染以後,會生成一個新的樹,將新樹與舊樹進行對比,就能夠最終得出應施加到真實DOM上的改動。最後再經過patch函數施加改動。函數

這樣作的主要緣由是,在瀏覽器當中,JavaScript的運算在現代的引擎中很是快,但DOM自己是很是緩慢的東西。當你調用原生DOM API的時候,瀏覽器須要在JavaScript引擎的語境下去接觸原生的DOM的實現,這個過程有至關的性能損耗。因此,本質的考量是,要把耗費時間的操做盡可能放在純粹的計算中去作,保證最後計算出來的須要實際接觸真實DOM的操做是最少的。性能

下面看渲染函數。用過React的開發者可能知道,React是沒有模板的,直接就是一個渲染函數,它中間返回的就是一個虛擬DOM樹。JSX實際就是一套用於讓咱們更簡單地去描述樹狀結構的語法糖。優化

以下圖所示,在Vue2.0當中,能夠看到就是說當好比左側的模板,通過Vue的編譯以後就會變成右側的東西。動畫

 

這個函數相似於建立一個虛擬元素的函數,咱們能夠給它一個名字,給它描述應該有的屬性特性和可能其餘的數據。而後後面這個最後這個參數是個數組,包含了該虛擬元素的子元素。總的來講2.0的編譯器作的就是這個活。code

同時,在Vue2.0裏,用戶能夠選擇直接跳過模板這一層去手寫渲染函數,同時也有可選JSX支持。從開發者的偏好以及開發者的效益的角度來考量,模板和JSX是各有利弊的東西。模板更貼近咱們的HTML,可讓咱們更直觀地思考語義結構,更好地結合CSS的書寫。JSX和直接渲染函數,由於是真正的JavaScript,擁有這個語言自己的全部的能力,能夠進行復雜的邏輯判斷,進行選擇性的返回最終要返回的DOM結構,可以實現一些在模板的語法限制下,很難作到的一些事情。對象

 

因此在Vue2.0裏,兩個都是能夠選擇的。在絕大部分狀況下使用模板,可是在須要複雜邏輯的狀況下,使用渲染函數。在Vue2.0的路由和內部的一些實踐上,都大量地應用渲染函數作複雜的抽象組件,好比過渡動畫組件以及路由裏面的link組件,都是用渲染函數實現的,同時還保留了它自己的依賴追蹤系統。

以下圖所示,Vue的依賴追蹤經過ES5的 Object.defineProperty 方法實現。好比,咱們給它一個原生對象,Vue會遍歷這個數據對象的屬性,而後進行屬性轉換。每個屬性會被轉換爲一個 getter 和一個 setter。同時每一個組件會有一個對應的 watcher 對象,這個對象的職責就是在當前組件被渲染的時候,記錄數據上面的哪些屬性被用到了。

例如,在渲染函數裏面用到A.B的時候,這個就會觸發對應的 getter。整個渲染流程具體要點以下:

  • 當某個數據屬性被用到時,觸發 getter,這個屬性就會被做爲依賴被 watcher 記錄下來。

  • 整個函數被渲染完的時候,每個被用到的數據屬性都會被記錄。

  • 相應的數據變更時,例如給它一個新的值,就會觸發 setter,通知數據對象對應數據有變化。

  • 此時會通知對應的組件,其數據依賴有所改動,須要從新渲染。

  • 對應的組件再次調動渲染函數,生成 Virtual DOM,實現 DOM 更新。

這樣一個流程跟主流的一些框架,例如React是有較大區別的。在React中,當組件複雜的時候須要用 shouldComponentUpdate 作優化。可是,它也有本身的各類坑,好比要確保該組件下面的組件不依賴外部的狀態。雖然說這在大部分狀況下是夠用的,但遇到極大複雜度的應用,遇到性能瓶頸的時候,這個流程優化起來也是至關複雜的一個話題。

以下圖所示,在Vue裏面因爲依賴追蹤系統的存在,當任意數據變更的時,Vue的每個組件都精確地知道本身是否須要重繪,因此並不須要手動優化。用Vue渲染這些組件的時候,數據變了,對應的組件基本上去除了手動優化的必要性。

相關文章
相關標籤/搜索