1、從官方文檔查看的Vue的生命週期鉤子
上面的圖片是從Vue的官網裏面找到的,若是單從這張圖去查看生命週期幹了什麼,咱們只能知道:vue
- 在beforeMount前會對給出的模板進行編譯(僅僅是在用Vue.js打包的時候會進行編譯,在用腳手架的時候,在打包過程當中會把模板編譯成爲渲染函數,這樣能夠避免每次建立一個Vue對象的時候進行編譯模板)
- 在mounted後,Vue實例對象纔是完整的對象,這個轉改可以維持到beforeDestroy。
可是咱們不知道的東西會有不少,我這裏就舉出幾個問題:算法
- 父子節點的生命週期執行順序是怎麼樣的?
- 每一個生命週期可以訪問到的數據是否相同?
- 咱們知道修改了data後可以觸發更新生命週期的鉤子,那麼究竟是怎樣進行觸發的?
- 咱們知道Vue的話是經過VNode來更新管理真實的DOM的,那麼在上面的生命週期何時進行渲染的?
爲何咱們要知道上面的狀況?由於咱們可能會遇到一些問題,須要知道Vue裏面的實現app
- 通常狀況下,咱們在組件初始化完畢的時候,也就是在mounted回調函數裏面調用咱們初始化的執行代碼(很大狀況下是請求,也就是異步操做),可是若是如今有一個性能的需求,就是要求儘早地調用咱們初始化的代碼,那麼選擇哪一個生命週期呢?這得根據每一個生命週期乾的事情來決定
- 對於一些全局同步的操做,好比解析路由來對應頁面顯示的內容等等這些操做,那麼咱們是想要它儘早地完成,以便全局使用。
在這裏的話,咱們能夠對我提出的第一個問題進行解決。如今場景是這樣的,咱們有一個父親組件(app.vue),還有一個子組件(index.vue),父親組件傳給子組件一個abc屬性(這個屬性綁定父親組件的abc數據),在建立頁面後,設定定時器,1s後更新abc屬性,兩秒後將父組件進行銷燬,那麼會出現什麼狀況呢?dom
咱們打印出了以上的信息,能夠進行回答上面提出的第一個問題:異步
- 父組件老是先於子組件建立,可是慢於子組件掛載節點
- 父組件老是在子組件進行更新完畢後再進行更新
- 父組件銷燬的時候會進行遞歸銷燬子組件
以上三點都是很容易理解緣由的,這裏就不進行解釋了。咱們如今已經知道的父子組件的生命週期執行順序了,接下來咱們看一下每一個生命週期鉤子前幹了什麼?ide
2、源碼上查看的生命週期鉤子(鉤子以前)
0.選項的合併
經過Vue的官方文檔,咱們有時候可以看到一個建立Vue實例的選項能夠有不一樣的寫法,那麼針對於不一樣的寫法,須要有一個工具來把這幾個不一樣的寫法進行規範化,這就是選項的合併的所要進行處理的內容。函數
1.beforeCreate
在這個鉤子函數前主要是對Vue實例進行屬性的初始化工具
- 生命週期狀態、監聽器的初始化,這些與業務邏輯無關
- 處理父組件對本組件的自定義事件的監聽,將其放到**_events**中
- 對建立VNode函數進行綁定,在Vue實例對象中,是不會存在直接對DOM進行操做的,而是經過建立VNode,而後經過patch的方式對DOM節點進行操做,操做的工具方法什麼的跟原生同樣的,Vue工具類裏面包含對這些方法的封裝。
- 對父組件傳進來的屬性(props)以及監聽事件(v-on)進行深度觀察
2.created
在這個鉤子函數以前主要是對數據進行初始化而且進行監聽操做:性能
- Injection、provide選項進行初始化
- 對於用戶定義的屬性進行初始化,如下是按順序來初始化,若是後面的屬性名與前面相同的話,會報錯:
- props:傳進來的屬性是父組件過來的,這個屬性不須要在子組件裏面進行觀察(由於父組件已經觀察它了)
- method:對設定的方法掛載到vm實例中,而且使用bind方法綁定函數上下文爲vm對象,這也就是爲何咱們使用箭頭函數的方式的時候,也是可以經過this訪問vm實例。
- data:在選項的合併的時候將data處理成一個可執行的函數,這裏的話,是將這個函數進行執行,獲得組件的數據,而且將全部數據進行深度觀測。
- computed:建立一個lazy型的觀察者,這個觀察者是不會主動去觸發的(若是計算屬性是函數的話,每次須要拿到值的時候進行調用函數,若是是普通值的話,則會直接獲取普通值)。這個計算屬性是不能直接賦值操做的(getter方法被設置成一個空函數,因此怎麼進行賦值也沒有用),因此是個lazy型的觀察者。computed的值只有在獲取的時候纔會執行而後拿到最新的值,因此它是一個懶求值。
- watch:對傳進來觀察的對象的路徑進行解析,拿到對應的屬性。建立一個觀察者,對這個屬性進行觀察,一旦屬性發生變化的時候,會觸發這個觀察者,調用傳進來的函數。
3.beforeMount
在掛載前的生命鉤子前會進行元素綁定以及渲染函數的操做:this
- vm.$el屬性賦值
- 渲染函數若是爲空,進行建立空的方法
4.mounted
在本生命週期前,會進行渲染函數觀察者的設定,當屬性改變的時候,會直接反映到頁面數據中。渲染函數觀察者爲何要在數據觀察者設定後進行建立的話,這個等到後面的講述Vue的觀察者篇章的時候再說。
這裏要注意到一點,在建立觀察者的時候,咱們能夠經過傳給觀察者一個before方法,這樣執行觀察者的函數前調用before方法。渲染函數觀察者會傳進一個before方法,這個方法只有一句話,就是將本組件的聲明週期改成beforeUpdate,也就是說在修改數據的時候,反映到頁面以前,組件會先進入到beforeUpdate生命週期。
5.beforeUpdate
上面一點也說明了,在beforeUpdate前是用戶的各項操做,只要修改了某個屬性值,那麼就會觸發這個生命週期鉤子。
6.updated
觸發beforeUpdate後,這時候是在清空調用觀察者隊列(queue是存放如今時間全部須要進行回調的觀察者的一個隊列,固然渲染函數觀察者也在裏面)。整個隊列執行完畢後會進行調用這個updated生命週期函數,在調用這個生命週期函數的時候,頁面從新渲染已經結束了,因此在updated生命週期鉤子函數前會作如下事情:
- 打補丁(patch函數),這個函數首先是使用diff算法實現對dom操做的最小化,而後diff算法完成後,使用方法來針對於VNode修改dom節點內容。
- 從新綁定修改後的dom節點,大家能夠在綁定vm對象的dom節點的屬性上看到**__vue__這個屬性,這個就是指向綁定的vm**。
7.beforeDestroy
僅僅是判斷是否正在被destroy,使用變量鎖(單線程下變量便可做爲鎖,無需使用原子操做)防止重複操做。
8.destroyed
這裏主要是對事件、觀察者的卸載,在這個生命週期鉤子函數前會執行如下事情:
- 觀察者的卸載(computed、watch、render)三個觀察者進行卸載。
- 對根數據的觀察者的卸載。
- 對VNode進行卸載,VNode的卸載會引起dom節點的刪除。
9.destroyed以後
這裏對於組件的產生的事件、監聽的事情進行卸載,以及將對應的dom節點的**__vue__**屬性設空,最後對父親節點的解綁。
3、回答問題
-
問題1在前面已經回答了,就不重複了
-
問題2:每一個生命週期可以訪問到的數據是否相同?
回答是不,在beforeCreate根本就拿不到數據。
可是在正常運行的聲明周期函數中(beforeMount到updated),數據是一致的。這是在修改數據的時候,在一個事件循環中先觀察者放到隊列中,而後觸發觀察者回調隊列的執行。不過在一個vm對象中,渲染函數觀察者老是在隊列最後執行的,並且執行beforeUpdate是在執行渲染函數觀察者回調函數以前執行的。換句話說,觸發beforeUpdate以前,$watch定義的方法已經執行完畢,該更新的數據已經更新了。
-
咱們知道修改了data後可以觸發更新生命週期的鉤子,那麼究竟是怎樣進行觸發的?
在上面已經說明地很清楚了,若是有不懂的地方能夠再去看一下整個流程。
-
咱們知道Vue的話是經過VNode來更新管理真實的DOM的,那麼在上面的生命週期何時進行渲染的?
在beforeUpdate和updated中間。