手把手带你使用TS封装一个发布订阅模式

128 阅读2分钟

什么是发布订阅

消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者存在。

实现思路

  • 定义一个发布者对象,它有一个缓存列表,用于存放订阅者对象的回调函数
  • 定义一个订阅方法,用于向缓存列表中添加回调函数
  • 定义一个取消订阅方法,用于从缓存列表中移除回调函数
  • 定义一个发布方法,用于遍历缓存列表,依次执行回调函数,并传递相关参数

代码编写

// 发布者对象类型,需要有一个发布方法emit、一个订阅方法on及一个取消订阅的方法remove
type eventClass = {
  emit: (name: string) => void
  on: (name: string, callback: Function) => void
  remove: (name: string, callback: Function) => void
}

// 支持自定义发布事件名称的类型
type ParamsKey = string | number | symbol
// 定义缓存列表的类型---事件名称:事件函数
type eventList = {
  [key: ParamsKey]:Array<Function>
}

// 具体实现
class Event implements eventClass{
  eventList:eventList
  constructor() {
    this.eventList = {}
  }
  // 发布方法
  emit(name:string, ...args:Array<any>) {
    // 获取对应消息类型的事件数组
    let events:Array<Function> = this.eventList[name]
    // 遍历事件数组并执行回调函数
    events.forEach(item => {
      item.apply(this, args)
    })
  }
  // 订阅方法
  on(name:string, callback:Function) {
    // 如果没有该消息的缓存列表,就创建一个空数组
    let fn:Array<Function> = this.eventList[name] || []
    fn.push(callback)

    this.eventList[name] = fn
  }
  // 移除方法
  remove(key:string, callback:Function) {
    // 如果有该消息的缓存列表
    if(this.eventList[key]) {
      // 遍历缓存列表
      for(let i = 0; i <= this.eventList[key].length - 1; i++) {
        // 如果存在该事件函数,就从缓存列表中删除
        if(this.eventList[key][i] === callback) {
          this.eventList[key].splice(i, 1)
        }
      }
    }
  }
}

export default new Event()