“乞丐版”发布订阅模式
今天室友问我,你能手写一个发布订阅模式吗?我:???,好像听说过是一个一对多的关系?好吧,我还是太菜了,那今天就先来搞一个简易版发布订阅模式瞅瞅,只实现发布和订阅功能。
1. 发布订阅模式是什么?
发布-订阅模式
是对象中一种一对多的依赖关系,当一个对象触发触发某一事件时,所有订阅该事件的对象都能得到通知。
举个🌰:假如有一个售楼处需要发布卖房消息,并且将消息发送给客户,首先能收到消息的客户一定是订阅了售房消息的客户,而能收到消息的客户一定是售楼处发布了消息之后才能接收到消息,且售楼处只有一个,客户则是多个,就对应了发布者与订阅者一对多的情况。
以此可以看出:
- 发布者:发布者发布信息(相当于例子中的售楼处)
- 订阅者:订阅者订阅发布者发布的信息(相当于例子中的客户)
2. 怎样实现发布订阅模式?
我们这个“乞丐版”发布订阅模式只有订阅和发布功能:
on(type, fn)
订阅事件,其中接收两个参数,type为订阅事件的事件名,fn为事件触发之后执行的回调函数;emit(type,...args)
发布事件,其中接收两个参数,type为发布的事件名,...args为传给订阅回调函数的参数;
简易版
我希望有这样一个类,可以实现发布和订阅功能,代码如下:
class EventEmitter {
constructor() {
this.events = new Map(); // 存放订阅事件
}
on(type, fn) { // 事件订阅,type 订阅事件的名称, fn 触发的回调函数
}
emit(type,...args) { // 事件发布,type 发布事件的名称, args 发布事件的额外参数
}
}
实现on()方法
已知on()接收两个参数,type为订阅事件的事件名,fn为事件触发之后执行的回调函数,只有发布事件执行了,才能触发fn,所以fn应该被存起来,放到emit()中执行,代码如下:
on(type, fn) {
if (!this.events.get(type)) { // 此事件没人订阅过
this.events.set(type, [fn]);
} else {
this.events.get(type).push(fn) // 同一个事件多人订阅
}
}
实现emit()方法
已知emit()接收两个参数,type为发布的事件名,...args为传给订阅回调函数的参数,其中我们还需要处理一下this的指向问题,每一个订阅事件的回调函数fn可能都不一样,所以需要apply
显示绑定一下,代码如下:
emit(type,...args) {
const handle = this.events.get(type) // 先读取到type
handle.forEach(fn => { // 将handle中的所有事件触发
fn.apply(this, args) // fn执行掉
})
}
简易版完整代码
class EventEmitter {
constructor() {
this.events = new Map();
}
on(type, fn) {
if (!this.events.get(type)) { // 此事件没人订阅过
this.events.set(type, [fn]);
} else {
this.events.get(type).push(fn) // 同一个事件多人订阅
}
}
emit(type,...args) {
const handle = this.events.get(type) // 先读取到type
handle.forEach(fn => { // 将handle中的所有事件触发
fn.apply(this, args) // fn执行掉
})
}
}
测试案例:
不接收参数:
const emits = new EventEmitter()
emits.on('sell', () => { // 订阅事件
console.log('小明去买房');
})
emits.on('sell', () => { // 订阅事件
console.log('李华去买房');
})
emits.on('sellcar', () => { // 订阅事件
console.log('小红去买车位');
})
emits.emit('sell') // 发布事件
接收参数:
const emits = new EventEmitter()
emits.on('sell', (e) => { // 订阅事件
console.log('小明去买房', e);
})
emits.on('sell', (e) => { // 订阅事件
console.log('李华去买房', e);
})
emits.on('sellcar', (e) => { // 订阅事件
console.log('小红去买车位', e);
})
emits.emit('sell',100) // 发布事件
总结
这真的是简便的不能再简便的一种写法了,如果亲们能接受的话,给个点赞捏~( ̄▽ ̄)~*