當用戶指定了watch中的deep屬性為true時,如果當時監控的屬性是數組類型,會對對象中的每一項進行求值,此時會將當前watcher存入到對應屬性的依賴中,這樣數組中對象發生變化時也會通知數據更新。內部原理就是遞歸,耗費性能 。
整體流程:
initWatch 初期化user watcher(1),user watcher在defineReactive的get中訂閱屬性的變化(2),在defineReactive的set時觸發notify(2),notify調用每個訂閱了改屬性變化的watcher的update(3),監聽 watcher 進入update的queueWatcher,在queueWatcher的nextTick中調用flushSchedulerQueue(4),flushSchedulerQueue中調用監聽watcher的run(5),在watcher.run中調用this.get,在this.get中判斷this.deep是否為true,為true則執行traverse,在traverse中會因為對屬性的取值觸發2的get方法,並且traverse遞歸調用,使當前watch監聽到對象內部的每一個屬性(6),進而調用用戶在watch屬性上定義的方法。
1、initWatch 初期化user watcher(src\core\instance\state.js)
function initWatch (vm: Component, watch: Object) { for (const key in watch) { const handler = watch[key] if (Array.isArray(handler)) { for (let i = 0; i < handler.length; i++) { createWatcher(vm, key, handler[i])//每一項創建一個watcher } } else { createWatcher(vm, key, handler) } } }
2、user watcher在defineReactive的get中訂閱屬性的變化,在defineReactive的set時觸發notify
export function defineReactive ( obj: Object, key: string, val: any, customSetter?: ?Function, shallow?: boolean ) { ... Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { const value = getter ? getter.call(obj) : val if (Dep.target) { dep.depend() if (childOb) { childOb.dep.depend() if (Array.isArray(value)) { dependArray(value) } } } return value }, set: function reactiveSetter (newVal) { ... dep.notify() } }) }
3、notify調用每個訂閱了改屬性變化的watcher的update
notify () { ... for (let i = 0, l = subs.length; i < l; i++) { subs[i].update() } }
4、queueWatcher(src\core\observer\scheduler.js):
export function queueWatcher (watcher: Watcher) { ... nextTick(flushSchedulerQueue) }
5、調用監聽watcher的run
function flushSchedulerQueue () { ... for (index = 0; index < queue.length; index++) { ... watcher.run() ... } ... }
6、traverse