js eventBus 事件总线(发布订阅模式)

804 阅读1分钟

js eventBus 事件总线(发布订阅模式)

事件总线:一种集中式事件处理机制,允许不同的组件之间进行彼此通信而又不需要相互依赖,达到一种解耦的目的。

class EventEmitter {
  constructor() {
    this.cache = {}
  }

  on(name, fn) {
    if (this.cache[name]) {
      this.cache[name].push(fn)
    } else {
      this.cache[name] = [fn]
    }
  }

  emit(name, ...args) {
    const tasks = this.cache[name] && this.cache[name].slice() // 创建副本,如果回调函数内继续注册相同事件,会造成死循环
    if (tasks) {
      for (const fn of tasks) {
        fn(...args)
      }
    }
  }

  once(name, fn) {
    const onceFn = (...args) => {
      fn(...args)
      this.off(name, onceFn)
    }

    onceFn.callback = fn
    this.on(name, onceFn)
  }

  off(name, offFn) {
    if (!offFn) {
      delete this.cache[name] // 没有指明要关闭哪个监听回调,就清空所有
    } else {
      const stask = this.cache[name]
      if (stask) {
        const index = stask.findIndex(fn => fn === offFn || fn.callback === offFn)
        if (index >= 0) {
          stask.splice(index, 1)
        }
      }
    }
  }
}

测试示例:

const eventBus = new EventEmitter()
const fn1 = function (name, age) {
  console.log(`fn1, ${name} ${age}`)
}
const fn2 = function (name, age) {
  console.log(`fn2, ${name} ${age}`)
}

console.log('%c测试 emit---', 'color:blue')
eventBus.on('test', fn1)
eventBus.on('test', fn2)
eventBus.emit('test', '小明', 10)

console.log('%c测试 once---', 'color:blue')
eventBus.once('onceTest', fn1)
eventBus.once('onceTest', fn2)
eventBus.emit('onceTest', '小明', 10)
eventBus.emit('onceTest', '小明', 10) // 此 emit 不会起效,因为 once 中已经清空了监听

console.log('%c测试 off---', 'color:blue')
eventBus.off('test', fn1)
eventBus.emit('test', '小明', 10) // 此 emit, fn1 不会起效,fn2 仍然有效

console.log('%c再次测试 off---', 'color:blue')
eventBus.on('test', fn1)
eventBus.on('test', fn2)
eventBus.off('test')
eventBus.emit('test', '小明', 10) // 此 emit 不会起效,因为没有指明要关闭哪个监听回调,off 清空所有