Vue源碼編譯過程
一、掛載
初始化$mounted會掛載組件,不存在 render 函數時需要編譯(compile);
二、compile
1.compile 分為 parse,optimize 和 generate,最終得到 render 函數;
2.parse 調用 parseHtml 方法,方法核心是利用正則解析 template 的指令,class 和 stype,得到 AST;
3.optimize 作用標記 static 靜態節點,后面 patch,diff會跳過靜態節點;
4.generate 是將 AST 轉化為 render 函數表達式,執行 vm._render 方法將 render 表達式轉化為VNode,得到 render 和 staticRenderFns 字符串;
5.vm._render 方法調用了 VNode 創建的方法createElement
// render函數表達式
(function() {
with(this){
return _c('div',{ //創建一個 div 元素
attrs:{"id":"app"} //div 添加屬性 id
},[
_m(0), //靜態節點 header,此處對應 staticRenderFns 數組索引為 0 的 render function
_v(" "), //空的文本節點
(message) //判斷 message 是否存在
//如果存在,創建 p 元素,元素里面有文本,值為 toString(message)
?_c('p',[_v("\n "+_s(message)+"\n ")])
//如果不存在,創建 p 元素,元素里面有文本,值為 No message.
:_c('p',[_v("\n No message.\n ")])
]
)
}
})
三、依賴收集與監聽
這部分是數據響應式系統
1.調用 observer(),作用是遍歷對象屬性進行雙向綁定;
2.在 observer 過程中會注冊Object.defineProperty的 get 方法進行依賴收集,依賴收集是將Watcher 對象的實例放入 Dep 中;
3.Object.defineProperty的 set 會調用Dep 對象的 notify 方法通知它內部所有的 Watcher 對象調用對應的 update()進行視圖更新;
4.本質是發布者訂閱模式的應用
四、diff 和 patch
diff 算法對比差異和調用 update更新視圖:
1.patch 的 differ 是將同層的樹節點進行比較,通過唯一的 key 進行區分,時間復雜度只有 O(n);
2.上面將到 set 被觸發會調用 watcher 的 update()修改視圖;
3.update方法里面調用patch()得到同級的VNode 變化;
4.update 方法里面調用createElm通過虛擬節點創建真實的 DOM 並插入到它的父節點中;
5.createElm實質是遍歷虛擬 dom,逆向解析成真實 dom;