11 实现发布订阅模式

简介:

发布订阅者模式,一种对象间一对多的依赖关系,但一个对象的状态发生改变时,所依赖它的对象都将得到状态改变的通知。

主要的作用(优点):

  1. 广泛应用于异步编程中(替代了传递回调函数)
  2. 对象之间松散耦合的编写代码

缺点:

  • 创建订阅者本身要消耗一定的时间和内存
  • 多个发布者和订阅者嵌套一起的时候,程序难以跟踪维护

实现的思路:

  • 创建一个对象(缓存列表)
  • on方法用来把回调函数fn都加到缓存列表中
  • emit 根据key值去执行对应缓存列表中的函数
  • off方法可以根据key值取消订阅
    class EventEmiter {
      constructor() {
        // 事件对象,存放订阅的名字和事件
        this._events = {}
      }
      // 订阅事件的方法
      on(eventName,callback) {
        if(!this._events) {
          this._events = {}
        }
        // 合并之前订阅的cb
        this._events[eventName] = [...(this._events[eventName] || []),callback]
      }
      // 触发事件的方法
      emit(eventName, ...args) {
        if(!this._events[eventName]) {
          return
        }
        // 遍历执行所有订阅的事件
        this._events[eventName].forEach(fn=>fn(...args))
      }
      off(eventName,cb) {
        if(!this._events[eventName]) {
          return
        }
        // 删除订阅的事件
        this._events[eventName] = this._events[eventName].filter(fn=>fn != cb && fn.l != cb)
      }
      // 绑定一次 触发后将绑定的移除掉 再次触发掉
      once(eventName,callback) {
        const one = (...args)=>{
          // 等callback执行完毕在删除
          callback(args)
          this.off(eventName,one)
        }
        one.l = callback // 自定义属性
        this.on(eventName,one)
      }
    }

测试用例

    let event = new EventEmiter()
    
    let login1 = function(...args) {
      console.log('login success1', args)
    }
    let login2 = function(...args) {
      console.log('login success2', args)
    }
    // event.on('login',login1)
    event.once('login',login2)
    event.off('login',login1) // 解除订阅
    event.emit('login', 1,2,3,4,5)
    event.emit('login', 6,7,8,9)
    event.emit('login', 10,11,12)  

发布订阅者模式和观察者模式的区别?

  • 发布/订阅模式是观察者模式的一种变形,两者区别在于,发布/订阅模式在观察者模式的基础上,在目标和观察者之间增加一个调度中心。
  • 观察者模式 是由具体目标调度,比如当事件触发,Subject 就会去调用观察者的方法,所以观察者模式的订阅者与发布者之间是存在依赖的。
  • 发布/订阅模式 由统一调度中心调用,因此发布者和订阅者不需要知道对方的存在。
Last Updated:
Contributors: leeguooooo