发布订阅模式
二、手搓一个发布订阅事件中心
==============
“纸上得来终觉浅,绝知此事要躬行”,所以根据定义,我们尝试实现一个JavaScript版本的发布订阅事件中心,看看会遇到哪些问题?
2.1 基本结构版
首先实现的 DiyEventEmitter
如下:
/**
* 事件发布订阅中心
*/
class DiyEventEmitter {
static instance: DiyEventEmitter;
private _eventsMap: Map<string, Array<() => void>>;
static getInstance() {
if (!DiyEventEmitter.instance) {
DiyEventEmitter.instance = new DiyEventEmitter();
}
return DiyEventEmitter.instance;
}
constructor() {
this._eventsMap = new Map(); // 事件名与回调函数的映射Map
}
/**
* 事件订阅
* @param eventName 事件名
* @param eventFnCallback 事件发生时的回调函数
*/
public on(eventName: string, eventFnCallback: () => void) {
const newArr = this._eventsMap.get(eventName) || [];
newArr.push(eventFnCallback);
this._eventsMap.set(eventName, newArr);
}
/**
* 取消订阅
* @param eventName 事件名
* @param eventFnCallback 事件发生时的回调函数
*/
public off(eventName: string, eventFnCallback?: () => void) {
if (!eventFnCallback) {
this._eventsMap.delete(eventName);
return;
}
const newArr = this._eventsMap.get(eventName) || [];
for (let i = newArr.length - 1; i >= 0; i–) {
if (newArr[i] === eventFnCallback) {
newArr.splice(i, 1);
}
}
this._eventsMap.set(eventName, newArr);
}
/**
* 主动通知并执行注册的回调函数
* @param eventName 事件名
*/
public emit(eventName: string) {
const fns = this._eventsMap.get(eventName) || [];
fns.forEach(fn => fn());
}
}
export default DiyEventEmitter.getInstance();
导出的 DiyEventEmitter
是一个“单例”,保证在全局中只有唯一“事件中心”实例,使用时候直接可使用公共方法
import e from “./DiyEventEmitter”;
const subscr