vue.js框架原理淺析

saucxs發表於2019-02-20

vue.js是一個非常優秀的前端開發框架,不是我說的,大家都知道。

首先我現在的能力,獨立閱讀原始碼還是有很大壓力的,所幸vue寫的很規範,通過方法名基本可以略知一二,裡面的原理不懂的地方多方面查詢資料,本文中不規範不正確的地方歡迎指正,學生非常願意接受各位前輩提出寶貴的建議和指導。

使用vue的版本是v2.5.13,採用了flow作為型別管理工具,關於flow相關內容選擇性忽略了,不考慮型別系統,只考慮實現原理,寫下這篇文章。

本文大概涉及到vue幾個核心的地方:vue例項化,虛擬DOM,模板編譯過程,資料繫結。


一、vue的生命週期


二、vue例項化

研究vue的例項化就要研究_init方法,此方法定義在src/core/instance/init.js下的initMixin中,裡面是對vue例項即vm的處理。其中包括開發環境下的代理配置等一些列處理,並處理了傳遞給建構函式的引數等,重點在一系列方法

    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm)
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')複製程式碼

初始化生命週期,初始化事件,初始化渲染,觸發執行beforeCreate生命週期方法,初始化data/props資料監聽,觸發執行created生命週期方法。

對應到生命週期示例圖,created方法執行結束,接下來判斷是否傳入掛載的el節點,如果傳入的話此時就會通過$mount函式把元件掛載到DOM上面,整個vue建構函式就執行完成了。以上是vue物件建立的基本流程。


三、模板編譯

掛載的$mount函式,此函式的實現與執行環境有關,在此只看web中的實現。

實現只有簡單的兩行,

1、判斷執行環境為瀏覽器,

2、呼叫工具方法查詢到el對應的DOM節點,

3、mountComponent方法來實現掛載,

這裡就涉及到了掛載之前的處理問題。

1、對於擁有render(JSX)函式的情況,元件可以直接掛載,

2、如果使用的是template,需要從中提取AST渲染方法(注意如果使用構建工具,最終會為我們編譯成render(JSX)形式,所以無需擔心效能問題),AST即抽象語法樹,它是對真實DOM結構的對映,可執行,可編譯,能夠把每個節點部分都編譯成vnode,組成一個有對應層次結構的vnode物件。

有了渲染方法,下一步就是更新DOM,注意並不是直接更新,而是通過vnode,於是涉及到了一個非常重要的概念。


四、虛擬dom

虛擬DOM技術是一個很流行的東西,現代前端開發框架vue和react都是基於虛擬DOM來實現的。

虛擬DOM技術是為了解決一個很重要的問題:瀏覽器進行DOM操作會帶來較大的開銷。

1、要知道js本身執行速度是很快的,

2、而js物件又可以很準確地描述出類似DOM的樹形結構,

基於這兩點前提,人們研究出一種方式,

通過使用js描述出一個假的DOM結構,每次資料變化時候,在假的DOM上分析資料變化前後結構差別,找出這個最小差別並且在真實DOM上只更新這個最小的變化內容,這樣就極大程度上降低了對DOM的操作帶來的效能開銷。

上面的假的DOM結構就是虛擬DOM,比對的演算法成為diff演算法,這是實現虛擬DOM技術的關鍵。

1、在vue初始化時,首先用JS物件描述出DOM樹的結構,

2、用這個描述樹去構建真實DOM,並實際展現到頁面中,

3、一旦有資料狀態變更,需要重新構建一個新的JS的DOM樹,

4、對比兩棵樹差別,找出最小更新內容,

5、並將最小差異內容更新到真實DOM上。

有了虛擬DOM,下面一個問題就是,什麼時候會觸發更新,接下來要介紹的,就是vue中最具特色的功能--資料響應系統及實現。


五、資料繫結

vue.js的作者尤雨溪老師在知乎上一個回答中提到過自己創作vue的過程,最初就是嘗試實現一個類似angular1的東西,發現裡面對於資料處理非常不優雅,於是創造性的嘗試利用ES5中的Object.defineProperty來實現資料繫結,於是就有了最初的vue。vue中響應式的資料處理方式是一項很有價值的東西。

vue官網上面其實有具體介紹,下面是一張官方圖片:

vue響應

響應實現的基本原理:

1、vue會遍歷此data中物件所有的屬性,

2、並使用Object.defineProperty把這些屬性全部轉為getter/setter,

3、而每個元件例項都有watcher物件,

4、它會在元件渲染的過程中把屬性記錄為依賴,

5、之後當依賴項的 setter被呼叫時,會通知watcher重新計算,從而致使它關聯的元件得以更新。

為什麼vue不能在IE8以下執行?

因為IE8不支援ES5,所以用不了Object.defineProperty方法,又因為Object.defineProperty無法shim,所以vue不支援IE8及以下不支援ES5的瀏覽器。