找回密码
 立即注册
首页 业界区 业界 发布订阅模式的TS实现

发布订阅模式的TS实现

恙髡 4 天前
简介

发布订阅模式是一种常用的用于解耦的模式。
它和观察者模式的区别在于:

  • 观察者模式:被观察者需要维护一个观察者的集合;
  • 发布订阅模式:通信双方互相不知道对方的存在,通过第三方事件总线进行通信。
发布订阅模式在前端领域很常见,例如:

  • Vue 框架中组件的$on和$emit方法;
  • Node.js 中 EventEmitter 中的 on和 emit 方法。
图示

  • 订阅者通过on方法注册事件:
    1.png

  • 发布者通过emit触发回调列表:
    2.png

    发布者和订阅者双方不知道各自的存在,它们仅通过Event Bus进行通信。
实现

事件总线最基本的两个方法是 on 和 emit 。
常见的设计还有两个方法是 off 和 once,off 用于注销事件,once 是 on 的特例,表示仅订阅一次。
函数签名
  1. type CallbackFn = (...args: any[]) => void;
  2. on(eventName: string, callback: CallbackFn): void;
  3. emit(enentName: string, ...args: any): void;
  4. off(eventName: string, callback: CallbackFn): void;
  5. once(eventName: string, callback: CallbackFn): void;
复制代码
实现思路

在事件总线中需要建立起事件名回调集合的映射:

  • 当on时,将回调添加到指定事件名的回调集合中;
  • 当emit时,遍历指定时间名的回调集合,依次执行其中的回调函数;
回调集合可以使用Set实现,也可以使用数组实现。
由于on的实现需要做去重,建议使用Set,比较方便。
once的实现:
once 可以基于 on 和 off 实现,先使用 on 注册,执行回调之后就执行 off 注销,从而实现仅触发一次。
代码

使用 TypeScript 实现。
首先声明一个回调函数的类型,简化后续代码:
  1. type CallbackFn = (...args: any[]) => void;
复制代码
然后是声明 EventBus 类,成员属性中使用对象建立起 “事件名与回调集合” 的映射关系:
  1. class EventBus{
  2.     events: Record<string, Set<CallbackFn>> = {};
  3.     constructor(){}
  4.        
  5.     on(eventName: string, callback: CallbackFn){ /* ... */ }
  6.     emit(eventName: string, ...args: any[]){/* ... */}
  7.     off(eventName: string, callback: CallbackFn){/* ... */}
  8.     once(eventName: string, callback: CallbackFn){/* ... */}
  9. }
复制代码
on
  1. on(eventName: string, callback: CallbackFn){
  2.     if(!this.events[eventName]){
  3.         this.events[eventName] = new Set();
  4.     }
  5.     this.events[eventName].add(callback);
  6. }
复制代码

  • 如果事件名不存在,则要初始化创建一个 Set 用于记录。
  • 如果事件名存在,则直接将回调添加到 Set 中。
这段代码可以通过 短路运算符 简化:
  1. on(eventName: string, callback: CallbackFn){
  2.     (this.events[eventName] ??= new Set()).add(callback);
  3. }
复制代码
emit

遍历回调集合就
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册