发布订阅模式
发布订阅模式有三个部分,发布者和订阅者是通过事件中心联系的,vue 中的 $on 和 $emit 就是使用发布订阅模式的,调用 $emit 的组件就是发布者,调用 $on 的组件就是订阅者,我们基于此简单模拟一下发布订阅模式:
订阅者
发布者
事件中心:
subs对象: 存储所有的事件名称和事件的键值对$on(): 注册事件,可以注册多个事件,且同个事件可以注册多个方法,所以subs中存储的对象格式为:{'event1': [fn1,fn2], 'event2': [fn], ...}$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()方法,事件发生时要做的事情
目标(发布者)
subs数组: 存储所有的观察者addSub(): 添加观察者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()
发布订阅模式和观察者模式的区别
发布订阅模式中的发布者和订阅者是通过事件中心统一调度的,所以发布者和订阅者不需要知道对方的存在。而观察者模式中的观察者和目标之间是相互依赖的。