什么是发布订阅模式
一种一对多的消息发布模式,发布者会将消息广播给所有订阅者
可以类比于微信公众号
用户(Subscriber)订阅公众号(Publisher)之后,发布者发布文章(Message),用户接收文章
注意点
-
需要先订阅,再发布
类似于mitt中,先on,再emit
-
最大的特点就是:解耦
每个子系统独立管理,系统消息不会因为少了几个订阅者而崩溃
-
通信是单向的,如果要双向通信,请考虑
请求/回复模式 -
增加系统复杂度
订阅者不知道是在哪里发布的(代码阅读性极差,代码维护成本高)
发布者不知道订阅者是否接收到消息
JS实现发布订阅模式
class EventMitter {
// 初始化事件列表
constructor() {
this.list = [];
}
// 订阅
on(type, handler) {
(this.list[type] || (this.list[type] = [])).push(handler);
return this;
}
// 取消订阅
off(type, handler) {
let fns = this.list[type];
// 不存在则直接退出
if (!fns) {
return false;
}
if (!handler) {
// 没有指定则全部删除,清空数组
fns && (fns.length = 0);
} else {
// 删除特定的handler
for (let i = 0; i < fns.length; i++) {
if (fns[i] == handler) {
fns.splice(i, 1);
break;
}
}
}
return this;
}
// 只执行一次
once(type, handler) {
let _this = this;
function f() {
_this.off(type, f);
handler.apply();
}
this.on(type, f);
return this;
}
// 发布
emit(type, data) {
const fns = this.list[type] || [];
fns.forEach((fn)=>{
fn(data);
})
return this;
}
}
// test code
const bus = new EventMitter();
function f1(e){
console.log('f1',e);
}
function f2(){
console.log('f2');
}
function f3(e){
console.log('f3',e);
}
function f4(e){
console.log('f4',e);
}
bus.on('f1',f1).on('f2',f2).on('f3',f3).once('f4',f4);
bus.emit('f1',1).emit('f2',2).emit('f3',3).emit('f4',4);
bus.off('f1',f1).off('f2',f1).off('f2',f2);
bus.on('f2',f2);
bus.on('f2',f2);
bus.emit('f2');
bus.off('f2');
bus.emit('f1');
bus.emit('f2');
bus.emit('f3');
bus.emit('f4');
/*
f1 1
f2
f3 3
f4 undefined
f2
f2
f3 undefined
*/