【Vue】watch中的deep:true源碼實現


當用戶指定了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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM