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)

    }

  }

三、观察者模式的优缺点

  被观察对象和观察者之间是抽象耦合,且耦合程度很低,有助于扩展与重用;能进行简单的广播通信,自动通知所有订阅的观察者;观察者并不知道其他观察者的存在,若直接对被观察目标操作,造成一系列的更新,可能产生意外情况。

猜你喜欢

转载自www.cnblogs.com/llx1996/p/9839161.html