什么是发布-订阅模式
1. 定义
发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。
订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。
2. 例子
比如我们很喜欢看某个公众号号的文章,但是我们不知道什么时候发布新文章,要不定时的去翻阅;这时候,我们可以关注该公众号,当有文章推送时,会有消息及时通知我们文章更新了。
上面一个看似简单的操作,其实是一个典型的发布订阅模式,公众号属于发布者,用户属于订阅者;用户将订阅公众号的事件注册到调度中心,公众号作为发布者,当有新文章发布时,公众号发布该事件到调度中心,调度中心会及时发消息告知用户。
具体实现如下
const eventHub = {
map: {
// click: [f1 , f2]
},
on: (name, fn)=>{
eventHub.map[name] = eventHub.map[name] || []
eventHub.map[name].push(fn)
},
emit: (name, data)=>{
const q = eventHub.map[name]
if(!q) return
q.map(f => f.call(null, data))
return undefined
},
off: (name, fn)=>{
const q = eventHub.map[name]
if(!q){ return }
const index = q.indexOf(fn)
if(index < 0) { return }
q.splice(index, 1)
}
}
eventHub.on('click', console.log)
eventHub.on('click', console.error)
setTimeout(()=>{
eventHub.emit('click', 'frank')
},3000)
也可以用 class 实现。
class EventHub {
map = {}
on(name, fn) {
this.map[name] = this.map[name] || []
this.map[name].push(fn)
}
emit(name, data) {
const fnList = this.map[name] || []
fnList.forEach(fn => fn.call(undefined, data))
}
off(name, fn) {
const fnList = this.map[name] || []
const index = fnList.indexOf(fn)
if(index < 0) return
fnList.splice(index, 1)
}
}
// 使用
const e = new EventHub()
e.on('click', (name)=>{
console.log('hi '+ name)
})
e.on('click', (name)=>{
console.log('hello '+ name)
})
setTimeout(()=>{
e.emit('click', 'frank')
},3000)