Skip to content

发布–订阅模式说明(对应 EventEmitter)

  • Dep(事件中心):独立的调度中心,负责维护订阅关系并广播事件
  • Sub(订阅者):注册到事件中心的回调函数,在事件触发时执行
  • Pub(发布者):主动向事件中心发布事件的调用方
  1. Dep 是一个事件调度中心,负责维护事件与订阅者的映射关系。 它对外提供 on / emit / off 等接口,用于解耦发布者订阅者

  2. Sub 是通过 on 注册到 Dep 的事件回调函数, 平时不执行,仅在对应事件被发布时由 Dep 调度执行。

  3. Pub 是事件的发布者,通过调用 emit 向 Dep 发布事件, 接收到事件后通知所有订阅该事件的 Sub 执行。

Dep 负责调度,Sub 负责执行,Pub 负责触发。

EventEmitter

js

// 调度中心 Dep
class EventEmitter {
  constructor() {
    // 存储事件及其对应的回调函数列表
    this.events = {}
  }

  // 订阅事件 Sub
  on(eventName, ...callback) {
    if (!this.events[eventName]) {
      this.events[eventName] = []
    }

    callback.forEach(item => {
      if(! Array.isArray(item)) {
        item = [item]
      }
      this.events[eventName].push(...item)
    })
  }

  // 发布事件 Pub
  emit(eventName, data) {
    const callbacks = this.events[eventName]
    if (callbacks) {
      callbacks.forEach(callback => callback(data))
    }
  }

  // 取消订阅事件 Sub
  off(eventName, ...callback) {

    if(! this.events[eventName]) return false

    if(!callback) {
      delete this.events[eventName]
      return true 
    }

    callback.forEach(back => {

      if(typeof back === 'function') {
        this.events[eventName] = this.events[eventName].filter(item => item !== back)
        return true
      }
    })

    return false
  }
}

调用 EventEmitter

js

const eventBus = new EventEmitter()

const isSwitch = boolean => (!!boolean ? "开" : "关")

const controlHomeAppliance = (onOff, homeApplianceName) => {
  console.log(`开关改变,当前${homeApplianceName}的模式为${isSwitch(onOff)}`)
}

const lightCallBack = onOff => controlHomeAppliance(onOff, '电灯')

const television = onOff => controlHomeAppliance(onOff, '电视')

// 将事件名为 switch 的函数收集起来
eventBus.on("switch", [lightCallBack, television])

// 删掉其中 switch 事件名中其中已经收集的一个函数
eventBus.off("switch", television)

// 一秒钟之后通知已经收集的函数执行
setTimeout(() => {
  eventBus.emit("switch", true)
}, 1000)

最后更新于: