Vue2观察者模式(发布订阅模式)

376 阅读3分钟

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第3篇文章,点击查看活动详情

依赖器收集目标对象(getter)的观察者,当目标对象的状态发生改变时,通知观察者(setter)

  • 目标对象(Target)

  • 依赖收集器(Dep):作用是收集观察者

    • Dep有个静态属性target,当观察者初始化时,会在观察者的构造方法里,执行观察者的get方法,在观察者的get方法里,观察者会把自己赋值给Dep.target,意味着当前的观察者是自己
    • dep.addSub方法把当前的观察者收集,存储到subs属性中
    • dep.notify方法会调用所有观察者的update方法
  • 观察者(Watcher):作用是监听目标对象的变化

    • Watcher的构造方法里执行get方法里,get方法里执行expOrFn,expOrFn中对目标对象进行求值,触发Dep收集观察者
    • 当目标对象更新时,会调用观察者的update方法,如果是同步更新则接着调用run方法,如果是异步更新则执行queueWatcher方法,但无论是同步更新还是异步更新,最终都会执行run方法
    • 在run方法里,执行get方法,重新求expOrFn的值,如果有cb参数,则调用cb函数,把新值和旧值当做实参传入

过程

目标对象通过observe函数,添加__ob__属性,属性包括一个observe实例,实例中有dep属性,这个属性指向依赖收集器;为了读写目标对象的属性,对其每一个属性执行definReactive函数,把属性转换成可读写的访问器属性;这个过程被称为数据劫持

当执行观察者get方法时,会触发目标对象属性的getter方法,在getter方法里收集观察者,这个过程就是“收集观察者

当目标对象属性变更时,会触发目标对象的setter方法,在setter方法里执行观察者的update方法,这个过程就是“通知观察者

图:

observe

observe函数创建一个Observer实例,在Observer构造函数里做了三件事

  • 首先new了一个依赖收集器,这个dep的作用是,当目标对象增删属性时,通知对目标对象“感兴趣”的观察者;

  • 给目标对象添加不可枚举的__ob__属性,指向Observer实例;

  • 最后遍历对象属性,并执行defineReactive函数。

defineReactive
  • 创建了一个dep实例,这个dep 在访问器属性的 getter/setter 中被闭包引用,这个dep的作用是当目标对象属性发生写操作时,通知“感兴趣”的观察者;

  • 如果属性是对象或者数组,则调用observe函数并把这个属性当做实参,目的是使目标对象深度可侦测;

  • 使用Object.defineProperty函数把目标对象属性转成访问器属性,在getter方法里,通过执行dep.depend方法,收集对当前属性“感兴趣”的观察者;在setter方法里,执行observe(newVal),把新增加的属性值变成可侦测的,并执行dep.notify(),通知对此属性“感兴趣”的所有观察者。