## 全局概覽
這一節筆者將為大家介紹一下 Vue.js 內部的整個流程,希望能讓大家對全局有一個整體的印象,然后我們再來逐個模塊進行講解。從來沒有了解過 Vue.js 實現的同學可能會對一些內容感到疑惑,這是很正常的,這一節的目的主要是為了讓大家對整個流程有一個大概的認識,算是一個概覽預備的過程,當把整本小冊認真讀完以后,再來閱讀這一節,相信會有收獲的。
首先我們來看一下筆者畫的內部流程圖。

大家第一次看到這個圖一定是一頭霧水的,沒有關系,我們來逐個講一下這些模塊的作用以及調用關系。相信講完之后大家對Vue.js內部運行機制會有一個大概的認識。
## 初始化及掛載

在 `new Vue()` 之后。 Vue 會調用 `_init` 函數進行初始化,也就是這里的 `init` 過程,它會初始化生命周期、事件、 props、 methods、 data、 computed 與 watch 等。其中最重要的是通過 `Object.defineProperty` 設置 `setter` 與 `getter` 函數,用來實現「**響應式**」以及「**依賴收集**」,后面會詳細講到,這里只要有一個印象即可。
初始化之后調用 `$mount` 會掛載組件,如果是運行時編譯,即不存在 render function 但是存在 template 的情況,需要進行「**編譯**」步驟。
## 編譯
compile編譯可以分成 `parse`、`optimize` 與 `generate` 三個階段,最終需要得到 render function。

### parse
`parse` 會用正則等方式解析 template 模板中的指令、class、style等數據,形成AST。
### optimize
`optimize` 的主要作用是標記 static 靜態節點,這是 Vue 在編譯過程中的一處優化,后面當 `update` 更新界面時,會有一個 `patch` 的過程, diff 算法會直接跳過靜態節點,從而減少了比較的過程,優化了 `patch` 的性能。
### generate
`generate` 是將 AST 轉化成 render function 字符串的過程,得到結果是 render 的字符串以及 staticRenderFns 字符串。
在經歷過 `parse`、`optimize` 與 `generate` 這三個階段以后,組件中就會存在渲染 VNode 所需的 render function 了。
## 響應式
接下來也就是 Vue.js 響應式核心部分。

這里的 `getter` 跟 `setter` 已經在之前介紹過了,在 `init` 的時候通過 `Object.defineProperty` 進行了綁定,它使得當被設置的對象被讀取的時候會執行 `getter` 函數,而在當被賦值的時候會執行 `setter` 函數。
當 render function 被渲染的時候,因為會讀取所需對象的值,所以會觸發 `getter` 函數進行「**依賴收集**」,「**依賴收集**」的目的是將觀察者 Watcher 對象存放到當前閉包中的訂閱者 Dep 的 subs 中。形成如下所示的這樣一個關系。

在修改對象的值的時候,會觸發對應的 `setter`, `setter` 通知之前「**依賴收集**」得到的 Dep 中的每一個 Watcher,告訴它們自己的值改變了,需要重新渲染視圖。這時候這些 Watcher 就會開始調用 `update` 來更新視圖,當然這中間還有一個 `patch` 的過程以及使用隊列來異步更新的策略,這個我們后面再講。
## Virtual DOM
我們知道,render function 會被轉化成 VNode 節點。Virtual DOM 其實就是一棵以 JavaScript 對象( VNode 節點)作為基礎的樹,用對象屬性來描述節點,實際上它只是一層對真實 DOM 的抽象。最終可以通過一系列操作使這棵樹映射到真實環境上。由于 Virtual DOM 是以 JavaScript 對象為基礎而不依賴真實平臺環境,所以使它具有了跨平臺的能力,比如說瀏覽器平臺、Weex、Node 等。
比如說下面這樣一個例子:
```
{
tag: 'div', /*說明這是一個div標簽*/
children: [ /*存放該標簽的子節點*/
{
tag: 'a', /*說明這是一個a標簽*/
text: 'click me' /*標簽的內容*/
}
]
}
```
渲染后可以得到
```
<div>
<a>click me</a>
</div>
```
這只是一個簡單的例子,實際上的節點有更多的屬性來標志節點,比如 isStatic (代表是否為靜態節點)、 isComment (代表是否為注釋節點)等。
## 更新視圖

前面我們說到,在修改一個對象值的時候,會通過 `setter -> Watcher -> update` 的流程來修改對應的視圖,那么最終是如何更新視圖的呢?
當數據變化后,執行 render function 就可以得到一個新的 VNode 節點,我們如果想要得到新的視圖,最簡單粗暴的方法就是直接解析這個新的 VNode 節點,然后用 `innerHTML` 直接全部渲染到真實 DOM 中。但是其實我們只對其中的一小塊內容進行了修改,這樣做似乎有些「**浪費**」。
那么我們為什么不能只修改那些「改變了的地方」呢?這個時候就要介紹我們的「**`patch`**」了。我們會將新的 VNode 與舊的 VNode 一起傳入 `patch` 進行比較,經過 diff 算法得出它們的「**差異**」。最后我們只需要將這些「**差異**」的對應 DOM 進行修改即可。
## 再看全局

回過頭再來看看這張圖,是不是大腦中已經有一個大概的脈絡了呢?
**那么,讓我們繼續學習每一個模塊吧!**