本篇代碼位於vue/src/core/instance/lifecycle.jsvue
初步探索完了核心類的實現以後,接下來就要開始深刻到Vue實現的具體功能部分了。在全部的功能開始運行以前,要來理解一下Vue的生命週期,在初始化函數中全部功能模塊綁定到Vue的核心類上以前,最早開始執行了一個初始化生命週期的函數initLifecycle(vm)
,先來看看這個函數作了些什麼。node
// 導出initLifecycle函數,接受一個Component類型的vm參數 export function initLifecycle (vm: Component) { // 獲取實例的$options屬性,賦值爲options變量 const options = vm.$options // 找到最上層非抽象父級 // locate first non-abstract parent // 首先找到第一個父級 let parent = options.parent // 判斷是否存在且非抽象 if (parent && !options.abstract) { // 遍歷尋找最外層的非抽象父級 while (parent.$options.abstract && parent.$parent) { parent = parent.$parent } // 將實例添加到最外層非抽象父級的子組件中 parent.$children.push(vm) } // 初始化實例的公共屬性 // 設置父級屬性,若是以前的代碼未找到父級,則vm.$parent爲undefined vm.$parent = parent // 設置根屬性,沒有父級則爲實例對象自身 vm.$root = parent ? parent.$root : vm // 初始化$children和$refs屬性 // vm.$children是子組件的數組集合 // vm.$refs是指定引用名稱的組件對象集合 vm.$children = [] vm.$refs = {} // 初始化一些私有屬性 // 初始化watcher vm._watcher = null // _inactive和_directInactive是判斷激活狀態的屬性 vm._inactive = null vm._directInactive = false // 生命週期相關的私有屬性 vm._isMounted = false vm._isDestroyed = false vm._isBeingDestroyed = false }
initLifecycle
函數很是簡單明瞭,主要是在生命週期開始以前設置一些相關的屬性的初始值。一些屬性將在以後的生命週期運行期間使用到。git
生命週期的開始除了設置了相關屬性的初始值以外,還爲類原型對象掛載了一些方法,包括私有的更新組件的方法和公用的生命週期相關的方法。這些方法都包含在 lifecycleMixin
函數中,還記得這也是在定義核心類以後執行的那些函數之一,也來看看它的內容。github
// 導出lifecycleMixin函數,接收形參Vue, // 使用Flow進行靜態類型檢查指定爲Component類 export function lifecycleMixin (Vue: Class<Component>) { // 爲Vue原型對象掛載_update私有方法 // 接收vnode虛擬節點類型參數和一個可選的布爾值hydrating Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) { // 定義實例變量 const vm: Component = this // 下面三條賦值操做主要是爲了存儲屬性 // 實例的$el屬性賦值給prevEl變量,這是新傳入的實例掛載元素 const prevEl = vm.$el // 實例的_vnode屬性賦值給prevVnode變量,儲存的舊虛擬節點 const prevVnode = vm._vnode // 將activeInstance賦值給prevActiveInstance變量,激活實例 // activeInstance初始爲null const prevActiveInstance = activeInstance // 下面是針對新屬性的賦值 // 將新實例設置爲activeInstance activeInstance = vm // 將傳入的vnode賦值給實例的_vnode屬性 // vnode是新生成的虛擬節點數,這裏把它儲存起來覆蓋 vm._vnode = vnode // 下面使用到的Vue.prototype .__ patch__方法是在運行時裏注入的 // 根據運行平臺的不一樣定義 // Vue.prototype.__patch__ is injected in entry points // based on the rendering backend used. // 若是prevVnode屬性不存在說明是新建立實例 // 執行實例屬性$el的初始化渲染,不然更新節點 if (!prevVnode) { // 若是舊的虛擬節點不存在則調用patch方法 // 傳入掛載的真實DOM節點和新生成的虛擬節點 // initial render vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */) } else { // 不然執行虛擬節點更新操做,傳入的是新舊虛擬節點 // updates vm.$el = vm.__patch__(prevVnode, vnode) } // 將以前的激活實例又賦值給activeInstance activeInstance = prevActiveInstance // 更新__vue__屬性的引用 // update __vue__ reference // 若是存在舊元素則設置它的__vue__引用爲null if (prevEl) { prevEl.__vue__ = null } // 若是實例的$el屬性存在,設置它的__vue__引用爲該實例 if (vm.$el) { vm.$el.__vue__ = vm } // 若是父節點是一個高階組件,也更新它的元素節點 // if parent is an HOC, update its $el as well if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) { vm.$parent.$el = vm.$el } // 更新的鉤子由調度器調用,以確保在父更新的鉤子中更新子項。 // updated hook is called by the scheduler to ensure that children are // updated in a parent's updated hook. } // 爲Vue實例掛載$forceUpdate方法,實現強制更新 Vue.prototype.$forceUpdate = function () { const vm: Component = this if (vm._watcher) { vm._watcher.update() } } // 爲Vue實例掛載$destroy方法 Vue.prototype.$destroy = function () { // 定義實例變量 const vm: Component = this // 若是實例已經在銷燬中,則返回 if (vm._isBeingDestroyed) { return } // 調用beforeDestroy鉤子 callHook(vm, 'beforeDestroy') // 給實例設置正在銷燬中的標誌 vm._isBeingDestroyed = true // 從父組件中移除自身 // remove self from parent const parent = vm.$parent // 若是非抽象父級組件存在且沒有在銷燬中,則從父組件中移除實例 if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) { remove(parent.$children, vm) } // 銷燬全部觀察器 // teardown watchers if (vm._watcher) { vm._watcher.teardown() } let i = vm._watchers.length while (i--) { vm._watchers[i].teardown() } // 移除對象引用 // remove reference from data ob // frozen object may not have observer. if (vm._data.__ob__) { vm._data.__ob__.vmCount-- } // 調用最後的鉤子 // call the last hook... // 設置實例的已銷燬標誌 vm._isDestroyed = true // 調用當前渲染樹上的銷燬鉤子 // invoke destroy hooks on current rendered tree vm.__patch__(vm._vnode, null) // 觸發銷燬鉤子 // fire destroyed hook callHook(vm, 'destroyed') // turn off all instance listeners. // 清除全部監聽事件 vm.$off() // 移除實例引用 // remove __vue__ reference if (vm.$el) { vm.$el.__vue__ = null } // 釋放循環引用 // release circular reference (#6759) if (vm.$vnode) { vm.$vnode.parent = null } } }
lifecycleMixin
函數實現了三個原型繼承方法:數組
這個函數用於更新組件,實現數據和元素節點的無刷新更新,涉及到虛擬節點相關的一些內容,具體實現留給將來研究虛擬節點和數據更新時再深刻探索。架構
實現組件強制刷新,這個方法是從實例上設置的watcher對象方法中引用而來,在生命週期初始化的時候爲實例設置了一個私有的_watcher屬性,在觀察者系統的功能模塊中具體實現了這一對象,也放到之後在去深刻了解。這裏只要知道能夠調用這個共有的API實現手動更新組件。ide
實例銷燬方法。在剛開始討論生命週期的開啓時,就瞭解到了這個銷燬Vue實例組件的方法,凡事都善始善終,從這裏能夠明白無誤的認識到,Vue實例是一個生命過程。那麼在Vue的生命過程當中有哪些重要的階段,是接下來要繼續探索的內容。函數
最明白無誤的生命週期過程在官方文檔中有介紹,這裏再貼上這張經典的圖示來作個記念。學習
對照生命週期圖示中呈現的各類鉤子函數,從源碼總結了他們的調用時機,順便又學習一遍鉤子執行的線路:this
initLifecycle(vm) initEvents(vm) initRender(vm) callHook(vm, 'beforeCreate')
從 new Vue()
建立實例開始 ,在執行 _init()
方法時開始初始化了生命週期、事件和渲染。緊接着就調用了 beforeCreate
鉤子函數。此時與數據相關的屬性都尚未初始化 ,因此在這個階段想要用獲取到組件的屬性是沒法成功的。
initInjections(vm) // resolve injections before data/props initState(vm) initProvide(vm) // resolve provide after data/props callHook(vm, 'created')
在 beforeCreate
調用後,繼續初始化屬性注入、狀態、子組件屬性提供器。而後當即調用 created
鉤子,這個時候數據可訪問了,可是尚未開始渲染頁面,適合一些數據的初始化操做。另外provide和injection主要爲高階插件/組件庫提供用例。並不推薦直接用於應用程序代碼中,因此此刻咱們主要注意的是觀察器的初始化完成。
到這一步以後,就開始進入渲染流程。
渲染的執行流程稍微複雜一些,實例裝載方法 $mount
是根據平臺的不一樣需求而分別定義的,在執行 $mount
方法的時候,開始裝載組件,具體內容在 mountComponent
函數中,在此函數的最開始時渲染虛擬節點以前就調用了 beforeMount
鉤子,而後開始執行 updateComponent
來渲染組件視圖。
緊接着上面視圖的渲染完成,mounted
鉤子被調用。在這個鉤子中還調用了內部的插入鉤子渲染引用的子組件,這以後就開始處於生命週期的正常運轉期。在這個時期內觀察器系統開始監控全部的數據更新,進入數據更新並從新渲染視圖的循環中。
在觀察器的做用下,若是有數據的更新時就會先調用 beforeUpdate
鉤子。
當數據更新而且完成視圖渲染後調用 updated
鉤子。這個鉤子和上面的鉤子會一直在生命週期運轉期裏不斷被觸發。
activated
和 deactivated
這兩個特殊鉤子是在使用 keep-alive
組件的時候纔有效。分別在組件被激活或切換到其餘組件的時候被調用。 使用 keep-alive
模式在切換到不一樣組件視圖的過程當中不會進行從新加載,這就意味着其餘的鉤子函數都不會被調用,若是在離開頁面和進入頁面的時候執行某些操做,這兩個鉤子就很是有用。
beforeDestroy
和 destroyed
鉤子與上面的兩個鉤子相對應,是在普通模式下會有效的鉤子。實例的生命週期的最後階段就是執行銷燬,在銷燬以前調用 beforeDestroy
。而後清除了全部的數據引用、觀察器和事件監聽器。最後調用 destroyed
宣告生命週期的徹底終止。
以前看過不少次Vue的生命週期圖,但在學習源碼以前並無特別深的感觸,如今隨着探索源碼的深刻,終於感受到在慢慢了解這個過程的意義。整個生命週期的構建過程並非最難的實現部分,但它是整個架構的背後支撐力量,有了生命週期的正常運轉,才能一步步地實現接下來要學習的各類功能。