浅显易懂的js发布-订阅模式

144 阅读3分钟

什么是发布订阅模式?

发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。

场景模式

举个例子:如我们平时去餐厅排队吃饭,需要拿了号慢慢排队,这时候假如本宝宝不想直接等而是想边逛街边等待,扫码微信订餐;当排队快到我的时候,就会有微信提醒信息,这时候我只要有提醒信息,就知道何时要吃饭。这里,我,相当于一个订阅者,餐厅则相当于发布者。我扫码订餐,相当于在注册信息。餐厅就有几种功能,一是可以接受用户发过来的信息;二是可以根据访问人数和排序,在微信上通知用户就餐;三是需要一个删除的操作,已经就餐完的用户就没必要继续去推送消息

思路方案

  • 创建一个餐厅的对象
  • 该对象有个可以装载事件,对事件进行管理的调度中心(微信)
  • on 注册事件,相当于该用户进行点餐操作
  • emit 根据不同的参数名,通知就餐
  • off 已经就餐完毕的用户可以取消监听

实现demo

class Restaurant {
  constructor () {
  }
  /**
   * 定义事件来装载事件数据
   */
  weixin = {}

  /**
   * 用户微信扫码
   * @param {String} type 事件名,相当于用户
   * @param {Function} fn 订阅事件,相当于订餐内容
   */
  on (type, fn) {
    if (!this.weixin[type]) {
      this.weixin[type] = []
    }
    this.weixin[type].push(fn)
  }

  /**
   * 通知就餐
   * @param {String} type 事件名,相当于用户
   * @param  {...any} message 参数
   */
  emit (type, ...message) {
    if (!this.weixin[type]) {
      return new Error('嘿,我都还没扫码订餐呢!')
    }
    // 通知用户就餐
    for (let i of this.weixin[type]) {
      i.call(this, ...message)
    }
  }

  /**
   * 删除就餐 (若无第二个参数则删除该事件的订阅和发布)
   * @param {String} type 事件名,相当于用户
   * @param {Function} fn 事件,相当于订餐内容
   */
  off (type, fn) {
    if (!type in this.weixin) {
      return new Error('咳咳!这人都没扫码点餐呢!')
    }
    if (!fn) {
      delete this.weixin[type]
    } else {
      const index = this.weixin[type].findIndex(item => item === fn)
      if (index === -1) {
        console.log('找不到这个点餐呢')
        return new Error('找不到这个点餐呢')
      }

      this.weixin[type].splice(index, 1)
      if (this.weixin[type].length === 0) {
        delete this.weixin[type]
      }
    }
  }
}

现在,基本的发布订阅模式已经完成拉!现在就让我们来测试一下

let rest = new Restaurant()
const beans = function () {
  console.log('来份豆子');
}
const banner = function () {
  console.log('来份香蕉派');
}
// 扫码订餐
rest.on('xiaoming', beans)
rest.on('xiaoming', banner)

rest.emit('xiaoming') // 来份豆子 来份香蕉派

rest.off('xiaoming', banner)
rest.off('xiaoming', banner) // 找不到这个点餐呢
rest.emit('xiaoming') // 来份豆子

结语

发布-订阅模式,是为了解决主题对象和订阅者之间功能的耦合,个人理解为的是监控数据和对现有对象的解耦。 例如你订餐的行为实际上就可以理解为一种监控;每人之间的订餐互不影响,这是解耦;

以上写法比较简单,如有不足之处,还望指出,多多学习!