vue2源碼框架和流程分析

vue總體框架和主要流程分析

以前對看過比較多關於vue源碼的文章,可是對於總體框架和流程仍是有些模糊,最後用chrome debug對vue的源碼進行查看整理出這篇文章。。。。javascript

本文對vue的總體框架和總體流程進行簡要的分析,不對某些具體的細節進行分析,全部須要對vue有初步的認識,包括對Object.defineProperty、虛擬DOM有必定了解,本文不會對Object.defineProperty、虛擬DOM的原理和細節進行分析。
vue大致能夠分兩個部分:

1.採用Object.defineProperty進行數據的雙向綁定;

2.採用虛擬DOM技術進行視圖渲染;vue

vue入口



vue構造函數調用了this._init(options)方法,這個方法在initMixin中,如上圖所示,進入initMixin


initMixin主要完成數據的初始化和視圖的初始化:

1.數據初始化主要是數據的observe,在上圖的initState中進行;

2.視圖的初始化在vm.$mount(vm.$options.el),其中vm爲Vue的實例,watcher的設置也是在vm.$mount(vm.$options.el)中完成的;

咱們能夠看到這裏定義了beforeCreated和created這兩個鉤子函數。java

數據初始化

接着上面咱們看看數據初始化都作了什麼,進入initState


這裏咱們主要對數據進行操做的是initData,傳入的是vm,咱們來具體看看initData:


咱們先忽略前面的一些邏輯判斷,主要看兩個地方:

1.數據代理,主要是將_data的數據代理到vm上,這樣的話能夠直接對vm上的數據進行修改;

2.數據observe,傳入data;

咱們先看看vue怎麼對數據進行observe的,進入observe


在observe裏返回的是ob,也就是Observer類的實例,咱們看看Observer類是怎麼定義的,進入Observer類


如上圖在對data進行observe時對數組進行了特殊的處理,這塊咱們先不看,先看通常狀況下的處理,即調用this.walk(value)


walk主要對data的屬性進行遍歷,進入defineReactive


能夠看到Object.defineProperty是在這裏對屬性設置get和set的,其中get主要進行依賴收集,其實就是在收集視圖渲染的watcher,後面會提到,set主要是數據更新時進行視圖的更新

至此,數據的初始化就完成了,從上面的分析來看,數據的初始化主要的工做就是對數據進行observe。git

視圖掛載

接着上面,在vue入口那裏,咱們知道視圖的掛載主要是調用了vm.$mount(vm.$options.el)


如圖,因此咱們進入vm.$mount,看看裏面都幹了啥,在源碼裏面有兩處地方涉及到$mount


這是第一處,就是return mountComponent




這是第二處,上面兩個圖是一塊兒的,屏幕大小有限,因此截了兩個圖。。。

我們看看第二處,裏面作了一個處理,就是將template編譯成render函數,在vue的教程裏有render函數的使用,這裏咱們能夠看出咱們在組件裏定義render函數會比定義template快,由於在定義template的組件掛載時多了一步將template編譯成render函數;

第二處的return 仍是調用了第一處,因此咱們看看第一處調用的mountComponent方法,進入mountComponent




上面兩個圖是一塊兒的,屏幕大小有限,因此截了兩個圖。。。

這裏咱們能夠看到定義了兩個鉤子beforeMount和mount,中間調用了watcher,咱們看一下這裏watcher的定義,這裏標註的不太好,擋住了。。。咱們看看watcher的這行代碼:
github

vm._watcher=new Watcher(vm,updateComponent,noop)

咱們能夠看到Watcher類主要傳入了vm,updateComponent,noop三個參數,其中updateComponent的主要做用是將虛擬DOM轉化爲真實的DOM並進行掛載,具體的細節下面在討論,咱們下面看看Watcher類是怎麼定義的,進入Watcher


這裏咱們注意兩個地方,一個是this.getter的定義,這裏就是上面傳進來的updateComponent,還有就是執行this.get(),咱們進入這個get方法


這裏咱們看到首先收集的依賴是當前watcher實例,而後調用getter方法也就是updateComponent方法,以前咱們對updateComponent方法的做用進行了簡單的說明,這裏咱們具體看看updateComponent都幹了啥,進入updateComponent:


這裏調用了vm._update方法,其中傳入的參數有vm._render(),_render函數主要的做用是產生虛擬DOM,進入_update


這裏主要是將虛擬DOM轉化爲真實DOM並進行掛載,分兩種狀況,分別是有舊的虛擬DOM和無舊的虛擬DOM,對應初始化時調用仍是數據更新時調用,這裏定義了一個鉤子beforeUpdate

到這裏,視圖的初始化和掛載也結束了,下面看看數據變化時視圖是如何更新的chrome

數據變化時視圖更新過程

接着上面咱們看看數據變化時視圖是怎麼變化的,在數據初始化的時候,咱們知道數據變化時將觸發set方法,以下圖:


上圖能夠看出,set最後調用了dep.notify,進入notify


如上圖,notify主要將收集的依賴,也就是收集的全部watcher,調用全部watcher的update方法,咱們看看watcher的updata方法幹了啥


這裏就是調用了queueWatcher,進入queueWatcher


這裏採用隊列異步更新,就是講=將watcher push進隊列queue中,而後執行nextTick方法,進入nextTick




上面兩個圖是一塊兒的,屏幕大小有限,因此截了兩個圖。。。

這個部分有點難看,cb爲傳入的flushSchedulerQueue函數,執行timerFunc,將nextTickHander加入異步隊列,執行nextTickHander,執行cb,既執行flushSchedulerQueue,進入flushSchedulerQueue




上面兩個圖是一塊兒的,屏幕大小有限,因此截了兩個圖。。。

主要看watcher.run(),進入watcher.run


執行了this.get(),即進入前面數據渲染和掛載的地方

到這裏,vue整個的執行流程基本就結束了。segmentfault

vue流程圖

盜用一下vue官網關於vue生命週期的圖,對照以前的內容梳理一下:



對照上面的分析基本上能夠找到各個鉤子函數的位置,下面那個銷燬的我就沒用作分析了。。。數組

你們有興趣的話能夠關注一下個人博客框架

相關文章
相關標籤/搜索