Observer、Dep、Watcher 傻傻搞不清楚

最近又回過頭來看 vue 的響應式原理,發現越看越迷了,ObserverDepWatcher 三者的做用是什麼,他們的的關係到底是怎樣的呢?javascript

Vue 初始化

我以爲搞清楚這些,首先要知道 vue 初始化的過程。咱們從 new Vue() 開始,構造函數會執行 this._init,在 _init 中會進行合併配置、初始化生命週期、事件、渲染等,最後執行 vm.$mount 進行掛載。vue

// src/core/instance/index.js
function Vue (options) {
    // ...
    this._init(options)
}

// src/core/instance/init.js
Vue.prototype._init = function (options?: Object) {
    // 合併配置
    // ...
    
    // 一系列初始化
    // ...
    initState(vm)
    // ...
    
    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
}
複製代碼

這裏主要來看 initState(vm),響應式的核心均在於此,會進行 propsdatacomputedwatch 的初始化操做。java

// src/core/instance/state.js
export function initState (vm: Component) {
    vm._watchers = []
    const opts = vm.$options
    if (opts.props) initProps(vm, opts.props) // 初始化 props
    // ...
    if (opts.data) {
        initData(vm) // 初始化 data
    } else {
        observe(vm._data = {}, true /* asRootData */)
    }
    // ...
}
複製代碼

瞭解了初始化過程,接下來就引出 Observerreact

Obserber 「數據的觀察者」

在上面的 initData 中會執行 observe 方法進而實例化 ObserverObserver 的實例化過程就是遞歸地把 data 對象和子對象添加 __ob__ 屬性同時經過咱們熟知的 defindReactive 爲屬性定義 getter/setter數組

那麼 Observer 顧名思義是觀察者,觀察的就是 data,它經過數據劫持使 data 的讀寫都處於它的監管之下。那麼在觀察到數據發生變化時會作出怎樣的操做呢?閉包

來到 defindReactive 的核心代碼,會看到 getter 裏的 dep.depend()setter 裏的 dep.notify(),這就是依賴收集和觸發更新的起點。這裏的 depdefindReactive 內定義的一個常量,getter/setter 函數內持有對它的閉包引用,Dep 就是引出的下一個概念。異步

// src/core/observer/index.js
// ...
const dep = new Dep()
// ...
Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () {
        // ...
        dep.depend()
        //...
    },
    set: function reactiveSetter (newVal) {
        // ...
        dep.notify()
    },
複製代碼

Dep 「依賴管理」

先看下 Dep 類的定義函數

// src/core/observer/dep.js
export default class Dep {
    constructor () {
        this.id = uid++
        this.subs = []
    }

    addSub (sub: Watcher) {}

    removeSub (sub: Watcher) {}

    depend () {}
    
    notify () {}
}
複製代碼

能夠看到 Dep 有一個實例屬性 subs 數組,實例方法 addSub/removeSub 添加和刪除數組中的某項。由此能夠肯定 dep 實例並不是依賴而是依賴的管理者,subs 數組即爲依賴(訂閱者)列表,它們就是接下來登場的 Watcheroop

Watcher 「訂閱者」

從上面知道 Observer Dep 都已經在 initState 中實例化了,響應式數據和依賴管理都準備好了,接下來就須要 Wacther 來訂閱了。那麼 Wacther 何時實例化呢,回到開頭的初始化過程最後 vm.$mount 掛載,在這以後會執行 mountComponent 方法,Watcher 就是在這裏實例化的(暫不關注 computed watcher 和 watch 選項的 watcher)。ui

// src/core/instance/lifecycle.js
export function mountComponent () {
    // ...
    new Watcher(vm, updateComponent, noop, {
        // ...
    }, true /* isRenderWatcher */)
}
複製代碼

Watcher 的定義以下,實例化時會執行 get 方法對傳入的 updateComponent 進行求值,updateComponent 也就是 _render 函數,執行 _render 函數會讀取 data 數據從而觸發 getter 進行依賴收集。

// src/core/observer/watcher.js
export default class Watcher {
    
    // 對 getter 求值,進行依賴收集
    get () {}
    
    // 觸發更新
    update() {}
}
複製代碼

總結

至此,咱們能夠總結一下三者的關係:

  • Observer 將數據定義爲響應式,每一個 Observer 實例都有本身的 Dep 來管理依賴。實例化 Wacther 的時候進行求值會觸發 getter ,進而執行 dep.depend() 將當前 Wacther 加入 Dep 維護的依賴列表,這就是依賴收集過程。
  • 數據發生變化觸發 setter 執行 dep.notifyDep 會執行全部依賴的 update 方法並加入異步更新隊列,這就是觸發依賴過程。

相關文章
相關標籤/搜索