简介
发布订阅模式是一种常用的用于解耦的模式。
它和观察者模式的区别在于:
- 观察者模式:被观察者需要维护一个观察者的集合;
- 发布订阅模式:通信双方互相不知道对方的存在,通过第三方事件总线进行通信。
发布订阅模式在前端领域很常见,例如:
- Vue 框架中组件的$on和$emit方法;
- Node.js 中 EventEmitter 中的 on和 emit 方法。
图示:
- 订阅者通过on方法注册事件:
- 发布者通过emit触发回调列表:
发布者和订阅者双方不知道各自的存在,它们仅通过Event Bus进行通信。
实现
事件总线最基本的两个方法是 on 和 emit 。
常见的设计还有两个方法是 off 和 once,off 用于注销事件,once 是 on 的特例,表示仅订阅一次。
函数签名
- type CallbackFn = (...args: any[]) => void;
- on(eventName: string, callback: CallbackFn): void;
- emit(enentName: string, ...args: any): void;
- off(eventName: string, callback: CallbackFn): void;
- once(eventName: string, callback: CallbackFn): void;
复制代码 实现思路
在事件总线中需要建立起事件名到回调集合的映射:
- 当on时,将回调添加到指定事件名的回调集合中;
- 当emit时,遍历指定时间名的回调集合,依次执行其中的回调函数;
回调集合可以使用Set实现,也可以使用数组实现。
由于on的实现需要做去重,建议使用Set,比较方便。
once的实现:
once 可以基于 on 和 off 实现,先使用 on 注册,执行回调之后就执行 off 注销,从而实现仅触发一次。
代码
使用 TypeScript 实现。
首先声明一个回调函数的类型,简化后续代码:- type CallbackFn = (...args: any[]) => void;
复制代码 然后是声明 EventBus 类,成员属性中使用对象建立起 “事件名与回调集合” 的映射关系:- class EventBus{
- events: Record<string, Set<CallbackFn>> = {};
- constructor(){}
-
- on(eventName: string, callback: CallbackFn){ /* ... */ }
- emit(eventName: string, ...args: any[]){/* ... */}
- off(eventName: string, callback: CallbackFn){/* ... */}
- once(eventName: string, callback: CallbackFn){/* ... */}
- }
复制代码 on- on(eventName: string, callback: CallbackFn){
- if(!this.events[eventName]){
- this.events[eventName] = new Set();
- }
- this.events[eventName].add(callback);
- }
复制代码
- 如果事件名不存在,则要初始化创建一个 Set 用于记录。
- 如果事件名存在,则直接将回调添加到 Set 中。
这段代码可以通过 短路运算符 简化:- on(eventName: string, callback: CallbackFn){
- (this.events[eventName] ??= new Set()).add(callback);
- }
复制代码 emit
遍历回调集合就
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |