发布订阅模式及手写发布订阅

129 阅读2分钟

发布订阅模式在很多地方都用到了,但是我自己经常忘记这块咋写,今天正好自己梳理一遍这块的逻辑

简介

发布订阅模式有两个角色

发布者:发布事件或者消息

订阅者:订阅了发布者的事件或消息,并在事件发生时做出响应

图解:

在订阅发布模式中,发布者将事件发送到事件总线或事件管理器中,然后订阅者订阅感兴趣的事件。当事件发生时,事件总线或事件管理器会通知所有订阅了该事件的订阅者,并调用它们预先注册的回调函数,从而实现了一种松耦合的通信方式。

自定义实现

发布、订阅功能

class EventEmitter {
  constructor() {
    this.list = {}
  }
  // 订阅事件
  on(event, callback) {
    if (!this.list[event]) {
      this.list[event] = []
    }
    this.list[event].push(callback)
  }
  // 触发事件
  emit(event, ...args) {
    if (this.list[event]) {
      this.list[event].forEach(fn => {
        fn.apply(this, args)
      });
    }
  }
}

function hello(...data) {
  console.log('hello' + data);
}

function world(...data) {
  console.log('world' + data);
}

const emitter = new EventEmitter()
// 订阅事件
emitter.on('onSell', hello)
emitter.on('onSell', world)
// 触发指定事件,执行对应的回调函数
emitter.emit('onSell', '1', '2', '3')

详细说明:

  • EventEmitter 类用于管理事件的订阅和触发。
  • on(event, callback) 方法用于订阅事件。当事件被触发时,对应的回调函数会被调用。
  • emit(event) 方法用于触发事件。当事件被触发时,所有订阅该事件的回调函数都会被依次调用。

输出:

hello1,2,3
world1,2,3

取消功能

class EventEmitter {
  constructor() {
    this.list = {}
  }
  // 订阅事件
  on(event, callback) {
    if (!this.list[event]) {
      this.list[event] = []
    }
    this.list[event].push(callback)
  }
  // 触发事件
  emit(event, ...args) {
    if (this.list[event]) {
      this.list[event].forEach(fn => {
        fn.apply(this, args)
      });
    }
  }
  // 取消订阅指定事件的指定回调函数
  off(event, callback) {
    if (this.list[event]) {
      this.list[event] = this.list[event].filter(fn => fn !== callback)
    }
  }
}

function hello(...data) {
  console.log('hello' + data);
}

function world(...data) {
  console.log('world' + data);
}

const emitter = new EventEmitter()
// 订阅事件
emitter.on('onSell', hello)
emitter.on('onSell', world)
emitter.off('onSell', hello)
// 触发指定事件,执行对应的回调函数
emitter.emit('onSell', '1', '2', '3')

详细说明:

  • off(event, callback) 方法用于取消订阅指定事件的指定回调函数。

输出:

world1,2,3

仅订阅一次事件功能

class EventEmitter {
  constructor() {
    this.list = {}
  }
  // 订阅事件
  on(event, callback) {
    if (!this.list[event]) {
      this.list[event] = []
    }
    this.list[event].push(callback)
  }
  // 触发事件
  emit(event, ...args) {
    if (this.list[event]) {
      this.list[event].forEach(fn => {
        fn.apply(this, args)
      });
    }
  }
  // 取消订阅指定事件的指定回调函数
  off(event, callback) {
    if (this.list[event] && callback) {
      this.list[event] = this.list[event].filter(fn => fn !== callback)
    }
  }
  // once方法用于仅订阅一次事件,即回调函数只会被执行一次
  once(event, callback) {
    const onceCallback = (...args) => {
      callback.apply(this, args)
      this.off(event, onceCallback)
    }
    this.on(event, onceCallback)
  }
}

function hello(...data) {
  console.log('hello' + data);
}

const emitter = new EventEmitter()
// 使用 once 方法订阅事件,回调函数只会被执行一次
emitter.once('onSell', hello)
// 触发事件,只会执行一次回调函数
emitter.emit('onSell', '1', '2', '3')
emitter.emit('onSell', '1', '2', '3') 

详细说明:

  • once(event, callback)方法用于订阅事件,但是事件在第一次被调用以后就被移除,相当于取消订阅,之后再次触发事件,订阅者也不会收到此事件的回调函数所发送的消息。

输出:

hello1,2,3

参考文章:juejin.cn/post/735605…