发布订阅
定义
发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。 订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。
实现
const eventhub = {
map:{},
on:(event,fn)=>{
eventhub.map[event] = eventhub.map[event] || [] //防御式编程,考虑参数为空的情况
eventhub.map[event].push(fn)
return undefined
},
off:(event,fn)=>{
const q = eventhub.map[event] //alias 别名、缩写,一般用于读操作,不用于写操作,否则可能会出现引用错误
if(!q) {return}
const index = q.indexOf(fn)
if(index < 0){return} // 短路
q.splice(index,1)
return undefined
},
emit:(event,data)=>{
const q = eventhub.map[event]
if(!q) return
q.map(fn =>{
fn.call(undefined,data)
})
return undefined
},
}
eventhub.on('click',console.log)
eventhub.on('click',console.error)
eventhub.off('click',console.log)
setTimeout(()=>{
eventhub.emit('click','jason')
})
用 class 实现
class EventHub{
map = {}
on(event,fn){
this.map[event] = this.map[event] || []
this.map[event].push(fn)
}
off(event,fn){
if(!this.map[event]) return
const index = this.map[event].indexOf(fn)
if(index < 0) return
this.map[event].splice(index,1)
}
emit(event,data){
const fnList = this.map[event] || []
fnList.forEach(fn => fn(data))
}
//先注册,事件执行后取消订阅
once(event,fn){
//需要在回调函数执行后,取消订阅当前事件,所以需要对传入的回调函数做一层包装,然后绑定包装后的函数
const onceFn = (...args)=>{
fn.call(undefined,...args)
this.off(event,onceFn)
}
this.on(event,onceFn)
}
}
const e = new EventHub()
e.on('click', (name)=>{
console.log('hi '+ name)
})
e.on('click', (name)=>{
console.log('hello '+ name)
})
setTimeout(()=>{
e.emit('click', 'jason')
},3000)