Vue中觀察者模式解析


一、觀察者模式簡介

  觀察者模式定義了對象間的一種一對多的組合關系,當一個對象的狀態發生變化時,所有依賴於它的對象都得到通知並自動刷新。觀察者模式必須包含兩個角色:觀察者和觀察對象,兩者之間存在“觀察”的邏輯關聯,當觀察對象狀態發生改變時,將通知相應的觀察者以更新狀態。

二、Vue中觀察者模式介紹

  項目源碼:https://github.com/vuejs/vue/tree/dev/src/core/observer

  下圖為Vue框架在數據初始化中使用觀察者模式的示意圖:

  (圖片來源:https://blog.csdn.net/github_36369819/article/details/79201314

  Dep類進行依賴收集,即通過subs數組記錄訂閱者(觀察者)Watcher,當數據狀態發生改變時,通知訂閱者Watcher進行數據更新(update)操作。以下列出了Dep類中部分方法的代碼,詳細代碼見:Dep.js

/**

 * A dep is an observable that can have multiple

 * directives subscribing to it.

 */

export default class Dep {

  static target: ?Watcher;

  id: number;

  subs: Array<Watcher>;



  constructor () {

    this.id = uid++

    this.subs = []

  }



  addSub (sub: Watcher) {

    this.subs.push(sub)

  }



  removeSub (sub: Watcher) {

    remove(this.subs, sub)

  }



  depend () {

    if (Dep.target) {

      Dep.target.addDep(this)

    }

  }



  notify () {

    // stabilize the subscriber list first

    const subs = this.subs.slice()

    if (process.env.NODE_ENV !== 'production' && !config.async) {

      // subs aren't sorted in scheduler if not running async

      // we need to sort them now to make sure they fire in correct

      // order

      subs.sort((a, b) => a.id - b.id)

    }

    for (let i = 0, l = subs.length; i < l; i++) {

      subs[i].update()

    }

  }

}



// the current target watcher being evaluated.

// this is globally unique because there could be only one

// watcher being evaluated at any time.

Dep.target = null

  Watcher類為觀察者,訂閱Dep類,能接受Dep類發出的數據更新通知進行update操作。以下代碼列出了Watcher類中主要的幾個方法:訂閱、更新等,詳細代碼見:Watcher.js

/**

   * Evaluate the getter, and re-collect dependencies.

   */

  get () {

    pushTarget(this)

    let value

    const vm = this.vm

    try {

      value = this.getter.call(vm, vm)

    } catch (e) {

      if (this.user) {

        handleError(e, vm, `getter for watcher "${this.expression}"`)

      } else {

        throw e

      }

    } finally {

      // "touch" every property so they are all tracked as

      // dependencies for deep watching

      if (this.deep) {

        traverse(value)

      }

      popTarget()

      this.cleanupDeps()

    }

    return value

  }



  /**

   * Add a dependency to this directive.

   */

  addDep (dep: Dep) {

    const id = dep.id

    if (!this.newDepIds.has(id)) {

      this.newDepIds.add(id)

      this.newDeps.push(dep)

      if (!this.depIds.has(id)) {

        dep.addSub(this)

      }

    }

  }



  /**

   * Clean up for dependency collection.

   */

  cleanupDeps () {

    let i = this.deps.length

    while (i--) {

      const dep = this.deps[i]

      if (!this.newDepIds.has(dep.id)) {

        dep.removeSub(this)

      }

    }

    let tmp = this.depIds

    this.depIds = this.newDepIds

    this.newDepIds = tmp

    this.newDepIds.clear()

    tmp = this.deps

    this.deps = this.newDeps

    this.newDeps = tmp

    this.newDeps.length = 0

  }



  /**

   * Subscriber interface.

   * Will be called when a dependency changes.

   */

  update () {

    /* istanbul ignore else */

    if (this.lazy) {

      this.dirty = true

    } else if (this.sync) {

      this.run()

    } else {

      queueWatcher(this)

    }

  }

三、觀察者模式的優缺點

  被觀察對象和觀察者之間是抽象耦合,且耦合程度很低,有助於擴展與重用;能進行簡單的廣播通信,自動通知所有訂閱的觀察者;觀察者並不知道其他觀察者的存在,若直接對被觀察目標操作,造成一系列的更新,可能產生意外情況。


免責聲明!

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



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