vue 响应式原理2

96 阅读1分钟

发布订阅模式

发布订阅模式有三个部分,发布者和订阅者是通过事件中心联系的,vue 中的 $on$emit 就是使用发布订阅模式的,调用 $emit 的组件就是发布者,调用 $on 的组件就是订阅者,我们基于此简单模拟一下发布订阅模式:

订阅者

发布者

事件中心

  1. subs对象: 存储所有的事件名称和事件的键值对
  2. $on(): 注册事件,可以注册多个事件,且同个事件可以注册多个方法,所以 subs 中存储的对象格式为:{'event1': [fn1,fn2], 'event2': [fn], ...}
  3. $emit(): 触发事件,接收事件名称参数,然后去 subs 中找对对应的事件并执行
class EventEmitter {
  constructor () {
    // 以 null 为原型创建对象可以提升性能
    this.subs = Object.create(null)
  }

  $on (eventType, handler) {
    this.subs[eventType] = this.subs[eventType] || []
    this.subs[eventType].push(handler)
  }

  $emit (eventType) {
    if (this.subs[eventType]) {
      this.subs[eventType].forEach(handler => {
        handler()
      })
    }
  }
}
// 测试
let em = new EventEmitter()
em.$on('click', () => {
  console.log('click1')
})
em.$on('click', () => {
  console.log('click2')
})
em.$emit('click')

观察者模式

观察者模式模式只有两个部分,观察者和目标是相互关联的。

观察者(订阅者)

具有 update()方法,事件发生时要做的事情

目标(发布者)

  1. subs数组: 存储所有的观察者
  2. addSub(): 添加观察者
  3. notify(): 事件发生时,调用所有观察者的 update() 方法

没有事件中心

class Dep {
  constructor () {
    this.subs = []
  }
  addSub (sub) {
    if (sub && sub.update) {
      this.subs.push(sub)
    }
  }
  notify () {
    this.subs.forEach(sub => {
      sub.update()
    })
  }
}
class Watcher {
  update () {
    console.log('update')
  }
}
// 测试
let dep = new Dep()
let watcher = new Watcher()
dep.addSub(watcher)
dep.notify()

发布订阅模式和观察者模式的区别

发布订阅模式中的发布者和订阅者是通过事件中心统一调度的,所以发布者和订阅者不需要知道对方的存在。而观察者模式中的观察者和目标之间是相互依赖的。 image.png