一、图解发布订阅
- 发布 - 订阅者模式其实是一种对象间一对多的依赖关系(利用消息队列)。
- 当一个对象的状态发生改变时,所有依赖于它的对象都得到状态改变的通知。
- 订阅者把自己想订阅的事件注册到调度中心,当发布者发布该事件到调度中心,也就是该事件触发时,由调度中心同意调度订阅者注册到调度中心的处理代码。
二、手写发布订阅
主要写一个事件调度中心,订阅主题($on
)、发布($emit
)、移除($off
)方法。
// 事件中心
class Observer {
constructor() {
/**
* message:{
* "abc":[handleA,handleB,handleC] // 主题:订阅者事件回调
* }
*/
this.message = {};
}
// 订阅
$on(type, fn) {
// 判断该主题是否存在
if (!this.message[type]) {
// 不存在就创建一个新的数组
this.message[type] = [];
}
this.message[type].push(fn);
}
// 移除
$off(type, fn) {
// 判断该主题是否存在
if (!this.message[type]) {
// 不存在直接返回
return;
}
// 判断是否只删除指定的订阅者(没传fn,说明是移除该主题)
if (!fn) {
delete this.message[type];
return;
}
// 将订阅者过滤,移除主题对应的订阅者
this.message[type] = this.message[type].filter((item) => item !== fn);
}
// 发布
$emit(type) {
// 判断该主题是否存在
if (!this.message[type]) {
// 不存在直接返回
return;
}
// 依次执行对应主题的事件回调
this.message[type].forEach((item) => {
item();
});
}
}
// 测试
// 创建事件中心
let observer = new Observer();
// 订阅主题
observer.$on("abc", handlerA);
observer.$on("abc", handlerB);
observer.$on("abc", handlerC);
console.log("订阅abc", observer);
/**
* 订阅abc Observer {
* message:{
* abc:[
* [Function: handlerA],
* [Function: handlerB],
* [Function: handlerC]
* ]
* }
* }
*/
// 移除主题 或 某主题对应的事件回调
observer.$off("abc", handlerA);
console.log("移除abc的handlerA", observer);
/**
* 移除abc的handlerA Observer {
* message: { abc: [ [Function: handlerB], [Function: handlerC] ] }
* }
*/
// 发布者发布,触发事件中心的某个主题对应的所有回调函数
observer.$emit("abc");
/**
* handlerB
* handlerC
*/
// 订阅者的回调函数
function handlerA() {
console.log("handlerA");
}
function handlerB() {
console.log("handlerB");
}
function handlerC() {
console.log("handlerC");
}