发布-订阅模式广泛应用于异步编程中,这是一种替代传递回调函数的方案。比如,我们可订阅 ajax
请求的 success
error
等事件,
发布订阅可以取代对象之间硬编码的通知机制,一个对象不用再显式地调用另外一个对象的接口。发布订阅模式让两个对象松耦合的联系在一起,虽然不清楚彼此的实现细节,但这并不影响他们之间的相互通信。
小明想买房,到了售楼处被告知,该楼盘的房子早已售罄。售楼MM告诉小明,不久后还有一些尾盘推出,时间还未定。 小明记下了售楼处的电话,以后每天都会打电话询问是否可购买。除了小明,还有小红、小强也会每天向售楼处咨询这个问题。可能售楼处每天回答 1000个相同内容的电话。 当然现实中销售公司会一一将客户的电话记录下来,新楼盘推出的时候,售楼 MM会翻开花名册,遍历上面的电话号码,依次发送一条短信来通知他们。
class Event {
constructor () {}
// 首先定义一个事件容器,用来装事件数组(因为订阅者可以是多个)
handlers = {}
// 事件添加方法,参数有事件名和事件方法
addEventListener (type, handler) {
// 首先判断handlers内有没有type事件容器,没有则创建一个新数组容器
if (!(type in this.handlers)) {
this.handlers[type] = []
}
// 将事件存入
this.handlers[type].push(handler)
}
// 触发事件两个参数(事件名,参数)
dispatchEvent (type, ...params) {
// 若没有注册该事件则抛出错误
if (!(type in this.handlers)) {
return new Error('未注册该事件')
}
// 便利触发
this.handlers[type].forEach(handler => {
handler(...params)
})
}
// 事件移除参数(事件名,删除的事件,若无第二个参数则删除该事件的订阅和发布)
removeEventListener (type, handler) {
// 无效事件抛出
if (!(type in this.handlers)) {
return new Error('无效事件')
}
if (!handler) {
// 直接移除事件
delete this.handlers[type]
} else {
const idx = this.handlers[type].findIndex(ele => ele === handler)
// 抛出异常事件
if (idx === undefined) {
return new Error('无该绑定事件')
}
// 移除事件
this.handlers[type].splice(idx, 1)
if (this.handlers[type].length === 0) {
delete this.handlers[type]
}
}
}
}
//使用这个单例模式
let event = new Event() // 创建event实例
// 定义一个自定义事件:"load"
function load (params) {
console.log('load', params)
}
event.addEventListener('load', load)
// 再定义一个load事件
function load2 (params) {
console.log('load2', params)
}
event.addEventListener('load', load2)
// 触发该事件
event.dispatchEvent('load', 'load事件触发')
// 移除load2事件
event.removeEventListener('load', load2)
// 移除所有load事件
event.removeEventListener('load')