Vue原始碼流程總結
阿新 • • 發佈:2020-08-24
1.Vue的初始化過程
1. 初始化生命週期
2. 初始化事件系統3. 初始化state,依次處理props, methods, data, computed ...
export function initState(vm: Component) { const opts = vm.$options if (opts.props) initProps(vm, opts.props) if (opts.methods) initMethods(vm, opts.methods) if (opts.data) initData(vm)4. 開始渲染 _mount() => _render() => 返回vdom => _update() => _patch() 更新domif (opts.computed) initComputed(vm, opts.computed) if (opts.watch) initWatch(vm, opts.watch) } }
2. Vue資料響應式原理
initData 初始化使用者資料
observe 將資料進行觀測
new Observer 定義觀測物件
this.walk(value) 迴圈處理物件的所有key
defineReactive 將物件的指定key定位為響應式
Object.defineProperty 在get和set方法種定義響應式,在get方法種用 Dep.depend 進行依賴收集
在set方法中用 dep.notify 進行依賴更新通知
// src/core/observer/dep.js let uid = 0 // Dep例項的id,為了方便去重 export default class Dep { static target: ?Watcher // 當前是誰在進行依賴的收集 id: number subs: Array<Watcher> // 觀察者集合 constructor() { this.id = uid++ // Dep例項的id,為了方便去重 this.subs = [] // 儲存收集器中需要通知的Watcher } addSub(sub: Watcher) { ... } /* 新增一個觀察者物件 */ removeSub(sub: Watcher) { ... } /* 移除一個觀察者物件 */ depend() { ... } /* 依賴收集,當存在Dep.target的時候把自己新增觀察者的依賴中 */ notify() { ... } /* 通知所有訂閱者 */ } const targetStack = [] // watcher棧 export function pushTarget(_target: ?Watcher) { ... } /* 將watcher觀察者例項設定給Dep.target,用以依賴收集。同時將該例項存入target棧中 */ export function popTarget() { ... } /* 將觀察者例項從target棧中取出並設定給Dep.target */
pushTaget和popTarget是和Dep類同級的方法,直接暴露給其他類使用
dep.notify() dep通知更新
subs[i].update() dep中的watcher呼叫update方法
queueWatcher 將watcher加入到佇列中
nextTick(flushSchedulerQueue) 在下一個tick,flush佇列,執行所有的watcher方法
5. nextTick方法實現原理
nextTick(cb) nextTick方法傳入回撥
callbacks.push(cb) 陣列儲存所有回撥
timerFunc 在timerFunc中呼叫回撥,timerFunc是用microTask模擬的,例如Promise.then, MutationObserver,setImmedate,setTimeout等
返回Promise 可以執行then方法
6. Vue的computed實現過程
initComputed
new Watcher
defineComputed
createComputedGetter 在此方法中進行依賴收集,和依賴計算,即執行watcher.evaluate方法
使用者取值 dirty = false 使用快取,返回上次結果,dirty = true watcher.evaluate(),重新計算結果
7. Vue的響應式更新過程
model更新 set方法 -> 觸發Dep.notify -> Dep的subs中的Watcher -> Watcher呼叫update -> queueWatcher -> nextTick -> flushQueueWatcher -> 生成新的Vnode -> 新VNode 與 老VNode 進行diff -> patch 將差異更新到檢視
diff是patch過程的核心。diff演算法有2個顯著特點:
1. 只會同級進行比較,不會垮層級比較
2. 在diff列表過程中,迴圈從兩邊向中間收攏
參考:
https://blog.csdn.net/MrWeb/article/details/105781370
https://www.cnblogs.com/kidney/p/8018226.html