『手写系列』两种方式实现订阅和发布

186 阅读1分钟

订阅和发布最常见的就是公众号了,关注公众号就是订阅,公众号新文章推送就是发布。细化到代码层面,订阅就是相当创建了一个键值对为 xxx: fn 的对象,当需要发布时,调用 fn 就可以。

1、声明一个对象

const eventHub = {
  map:{
    // click:[f1,f2]   // 每多一人订阅,index + 1。
  },
  // 订阅
  on:(name,fn)=>{
    eventHub.map[name]=[] || eventHub.map[name]
    eventHub.map[name].push(fn)
  }
  // 取消订阅
  off:(name,fn)=>{
    const value = eventHub.map[name]
    if(!value) return
    const index = value.indexOf(fn)
    if(index<0) return
    value.splice(index,1)
  }
  // 发布(新数据)
  emit:(name,data)=>{
    const value = eventHub.map[name]
    if(!value) return
    value.map(f=>f(data))  // 依次向每个订阅者发布
  }
}

// 使用
eventHub.on('click', value => console.log('我是第一个订阅者;' + value))  
eventHub.on('click', value => console.log('我是第二个订阅者;' + value))  
setTimeout(eventHub.emit('click', '数据已更新'), 3000)
eventHub.off('click', value => console.log('我是第二个订阅者;' + value))

2、使用类实现发布订阅

class EventHub = {
  map = {}
  on(name,fn)=>{
    this.map[name]=[] || this.map[name]
    this.map[name].push(fn)
  }
  off(name,fn)=>{
    const value = this.map[name]
    if(!value) return
    const index = value.indexOf(fn)
    if(index<0) return
    value.splice(index,1)
  }
  emit(name,data)=>{
    const value = this.map[name]
    if(!value) return
    value.forEach(f=>f(data))
  }
}

// 使用
const e = new EventHub()
e.on('click', value => console.log('我是第一个订阅者;' + value))  
e.on('click', value => console.log('我是第二个订阅者;' + value))  
setTimeout(e.emit('click', '数据已更新'), 3000)
e.off('click', value => console.log('我是第二个订阅者;' + value))