概念
这本书描述的比较清楚,不做赘述: 《Javascript设计模式与开发实践》
实现
核心API
- on 添加一个事件监听
- once 添加一个事件监听,当触发一次后就移除监听
- emit 触发事件
- off 移除事件监听
基本结构
interface IEvent {
listener: Function;
once: boolean;
}
interface Events {
[eventName: string]: IEvent[];
}
class EventBus {
events: Events = {}; // 缓存所有添加的事件
// 触发事件
emit(eventName: string, ...args) {}
// 添加一个事件监听
on(eventName: string, listener: Function, once?: boolean) {}
// 添加一个事件监听,当触发一次后就移除监听
once(eventName: string, listener: Function) {}
// 移除事件监听
off(eventName: string, listener?: Function) {}
}
基本实现
interface IEvent {
listener: Function;
once: boolean;
}
interface Events {
[eventName: string]: IEvent[];
}
class EventBus {
events: Events = {}; // 缓存所有添加的事件
// 触发事件
emit(eventName: string, ...args) {
if (!this.events[eventName]) return;
for (const event of this.events[eventName]) {
const { listener, once } = event;
listener(...args);
if (once) {
this.off(eventName, listener);
}
}
}
// 添加一个事件监听
on(eventName: string, listener: Function, once?: boolean) {
const event = { listener, once: !!once };
// 已添加
if (this.events[eventName]) {
this.events[eventName].push(event);
} else {
this.events[eventName] = [event];
}
}
// 添加一个事件监听,当触发一次后就移除监听
once(eventName: string, listener: Function) {
this.on(eventName, listener, true);
}
// 移除事件监听
off(eventName: string, listener?: Function) {
if (!this.events[eventName]) return;
if (listener) {
this.events[eventName] = this.events[eventName].filter(
(event) => event?.listener !== listener
);
} else {
delete this.events[eventName];
}
}
}
// on方法中判断是否已经添加了该事件的逻辑,可以不用if判断,也可以这样写
on(eventName: string, listener: Function, once?: boolean) {
const event = { listener, once: !!once };
// 已添加
// if (this.events[eventName]) {
// this.events[eventName].push(event);
// } else {
// this.events[eventName] = [event];
// }
// 不用if,更简洁的写法
this.events[eventName] = this.events[eventName] || [];
this.events[eventName].push(event);
}
单例模式
通常一个简单的项目使用一个实例做全局的通信就够了,过度使用发布订阅模式代码不易维护且不好排查问题。甲new一个,乙new一个,丙添加到甲,触发到乙,丙迷茫了开始排查问题……
interface IEvent {
listener: Function;
once: boolean;
}
interface Events {
[eventName: string]: IEvent[];
}
class EventBus {
events: Events = {};
private static instance: EventBus;
static getInstance() {
if (!EventBus.instance) {
EventBus.instance = new EventBus();
}
return EventBus.instance;
}
emit(eventName: string, ...args) {}
on(eventName: string, listener: Function, once?: boolean) {}
once(eventName: string, listener: Function) {}
off(eventName: string, listener?: Function) {}
}
// 注意这里导出的是:
export default EventBus.getInstance();
多说点啥
发布订阅模式工作中经常会用到,比如IM通信、微前端子应用通信、Vue的$on $emit、Node的EventBus…… 理解其原理为高效工作和阅读源码打好基础。Happy coding!