Skip to main content

发布订阅模式

基于一个事件(主题)通道,希望接收通知的对象 Subscriber 通过自定义事件订阅主题,被激活事件的对象 Publisher 通过发布主题事件的方式通知各个订阅该主题的 Subscriber 对象。

class 版

思路:

  1. 声明事件对象 map={}

  2. on 监听

    • map 中存在获取原数组 / 不存在则创建新数组
    • 把回调函数 fn 存入 map 事件数组
  3. emit 触发

    • 获取对应事件数组
    • 数组不存在则 return
    • 存在 map 遍历执行 fn
  4. off 取消

    • 获取对应事件数组
    • 数组不存在则 return
    • 函数不存在则 return
    • 存在 splice 删除
class EventHub {
map = {}
on(type,fn){
// key:存在就是原数组 / 不存在则创建新数组
this.map[type] = this.map[type] || []
// value
this.map[type].push(fn)
}
emit(type,args){
// 获取函数数组
const q = this.map[type]
// 是否数组为空
if(!q) return
// 执行函数数组
q.map(fn => fn.call(undefined,args))
}
off(type,fn){
// 获取函数数组
const q = this.map[type]
// 是否数组为空
if(!q) return
// 数组中对应函数是否存在
const index = q.indexOf(fn)
if(index < 0)return
// 删除:取消监听
q.splice(index,1)
}

}

使用方法:

// 使用
const e = new EventHub()

e.on('click', console.log)
e.on('click', console.error)

setTimeout(() => {
e.emit('click', 'frank')
}, 3000)

e.off('click', console.log)

观察者模式中 Subject 对象一般需要实现以下 API:

subscribe(): 接收一个观察者 observer 对象,使其订阅自己 unsubscribe(): 接收一个观察者 observer 对象,使其取消订阅自己 fire(): 触发事件,通知到所有观察者

函数版

// 被观察者
function Subject() {
this.observers = []
}

// 被观察者方法
Subject.prototype = {
// 订阅
subscribe:function (observer) {
this.observers.push(observer)
},
// 订阅订阅
unSubscribe:function (observerToRemove) {
this.observers = this.observers.filter(observer=>{
return observer !== observerToRemove
})
},
// 事件触发
fire:function () {
this.observers.forEach(observer => {
observer.call()
});
}
}

验证一下订阅是否成功:

const subject = new Subject()

function observer1() {
console.log('Observer 1 Firing!')
}

function observer2() {
console.log('Observer 2 Firing!')
}

subject.subscribe(observer1)
subject.subscribe(observer2)
subject.fire()

输出:

Observer 1 Firing!
Observer 2 Firing!

验证一下取消订阅是否成功:

subject.unSubscribe(observer2);
subject.fire();

输出:

Observer 1 Firing!