手写发布和订阅

127 阅读1分钟
const eventbus = {
  map: {
    
  },
  on: ( name , fn ) => {
    eventbus.map[ name ] = eventbus.map[name] || []
    eventbus.map[name].push(fn)
  },
  emit: ( name , data ) => {
    const q = eventbus.map[name]
    if(!q) return
    q.map(f => f.call(undefined,data))
  },
  off: ( name , fn ) => {
    const q = eventbus.map[name]
    if(!q) {return}
    const index = q.indexOf(fn)
    if(index < 0 ) {return}
    q.splice( index , 1 )
  }
}

eventbus.on('click',console.log)
eventbus.on('click',console.error)
setTimeout( () => {
  eventbus.emit('click' , 'young')
} , 3000)

也可以用 class 来实现

class Eventbus {
  constructor(){
    this.map = {}
  }
  on( name , fn ) {
    this.map[ name ] = this.map[name] || []
    this.map[name].push(fn)
  }
  emit ( name , data ) {
    const q = this.map[name]
    q?.map(f => f.call(undefined,data))
  }
  off ( name , fn ) {
    const q = this.map[name]
    if(!q) {return}
    const index = q.indexOf(fn)
    if(index < 0 ) {return}
    q.splice( index , 1 )
  }
}

const e = new Eventbus()
e.on('click',console.log)
e.on('click',console.error)
setTimeout( () => {
  e.emit('click' , 'young')
} , 3000)

发布订阅模式的特点:

  • api 提供了 on/off/emit (或其他意思一样的表达),满足上述条件会被称为 EventEmitter,实现了发布订阅模式。

本质是把回调函数放在队列里,等待被逐个调用 发布订阅解决了什么问题?

  • 所有异步任务都可以用发布订阅来管理
  • 先订阅成功事件和失败事件
  • 再在任务完成得时触发成功或失败案件
  • 是一个通用得异步任务管理方案
  • 可以用于将代码解耦

缺点是

  • 事件过多时,很难管理