介绍
发布-订阅是一种消息范式,通过定义发布者、订阅者、调度中心来完成消息通信。这是前端常用的消息通讯模式。
事件由调度中心统一管理,由订阅者在调度中心订阅(注册)事件,发布者通过调度中心发布(触发)事件,订阅者通过事件收到消息,以达到消息通信。
优点
- 松耦合:由于发布者和订阅者并不直接通信,而是通过和调度中心交互,达到消息广播和接收的目的。对象之间无需关心对方。
缺点
-
创建订阅者需要消耗一定的时间和内存。
-
虽然可以弱化对象之间的联系,如果过度使用的话,反而使代码不好理解及代码不好维护等等。
JS 实现
eventBus.map
: 存储事件队列的map
, 每个事件都有一个单独的队列,存放所有的事件处理函数eventBus.on(eventName, handler)
: 订阅事件的方法,根据传入的eventName
事件名,将handler
追加到新建或存在的事件队列中eventBus.emit(eventName, args)
: 触发事件的方法,根据传入事件名称、参数遍历事件队列并触发事件eventBus.off(eventName, handler)
: 取消事件订阅,根据事件名和处理函数取消事件订阅,如不传入处理函数,则清空相应的事件队列eventBus.once(eventName, handler)
: 执行单次事件订阅,触发后自动清除订阅
const eventBus = {
// map: 存储事件队列的 map, 每个事件都有一个单独的队列,存放所有的事件处理函数
map: new Map(),
// on: 订阅事件的方法,根据传入的 eventName 事件名,将handler追加到新建或存在的事件队列中
on(eventName, handler) {
const handlers = this.map.get(eventName)
if (handlers) {
handlers.push(handler)
} else {
this.map.set(eventName, [handler])
}
},
// emit: 触发事件的方法,根据传入事件名称、参数遍历事件队列并触发事件
emit(eventName, args) {
const handlers = this.map.get(eventName)
console.log(handlers)
if (!handlers) {
throw new Error(`${eventName} is not exist`)
}
handlers.forEach((handler) => {
handler(args)
})
},
// off: 取消事件订阅,根据事件名和处理函数取消事件订阅,如不传入处理函数,则清空相应的事件队列
off(eventName, handler) {
if (!handler) {
this.map.set(eventName, [])
return
}
const handlers = this.map.get(eventName)
const index = handlers.indexOf(handler)
if (index >= 0) {
handlers.splice(index, 1)
}
},
// once: 执行单次事件订阅,触发后自动清除订阅
once(eventName, handler) {
const tempHandler = (args) => {
this.off(eventName, tempHandler)
handler(args)
}
this.on(eventName, tempHandler)
},
}
复制代码
可以使用Map自带的clear清空EventBus
eventBus.map.clear()
其他
DOM
的 Eevnt
事件方法也是一个典型的发布-订阅模式。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END