js简单实现一个订阅-发布

201 阅读2分钟

什么是订阅和发布

发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。它可以使程序之前相互通信由不必彼此直接互相依赖

什么场景会用到订阅和发布

举个例子,当你在浏览一个新闻网站的时候,你可以订阅你感兴趣的博主,自此之后,每当博主发布了新的文章,都会给你推送他新发布的文章,(对于订阅者来说)你可以订阅多个博主;(对于发布者来说)博主也可具有多个订阅者

根据场景实现一个小demo

  1. 小明和小张都订阅了娱乐博主,当娱乐博主发送推送的时候,小张和小明都能收到消息
    let starBlogger = {} 
    starBlogger.list = []
    // on是订阅方法,将每个订阅者都放入list中
    starBlogger.on = function (fn) {
      this.list.push(fn)
    }
    // emit是发布方法,一旦触发emit,就会依次执行list里的函数
    starBlogger.emit = function (data) {
      this.list.forEach((cb) => {
        cb(data)
      })
    }
    // function (message){……},会被push进list中,等待有emit被触发时执行
    // 小明订阅了明星专栏
    starBlogger.on(function (message) {
      console.log('小明订阅了明星专栏:' + message)
    })
    // 小张订阅了明星专栏
    starBlogger.on(function (message) {
      console.log('小张订阅了明星专栏:' + message)
    })
    // 明星专栏进行发布,触发emit
    starBlogger.emit('XXX 结婚')
    starBlogger.emit('YYY 公布恋情')

  1. 升级版!!!小明关注了娱乐博主,小张也关注了足球博主,两个博主分别对小张小明进行推送,互不干扰
    let newsBlogger = {}
    newsBlogger.list = []
    // key代表了用户订阅的博主
    newsBlogger.on = function (key, fn) {
      if (!this.list[key]) {
        this.list[key] = []
      }
      this.list[key].push(fn)
    }
    // 传入的key值代表要推送新闻的博主
    newsBlogger.emit = function (key, data) {
      // this.list[key]内存放的是订阅了该博主的所有用户,要对他们进行推送
      let a = this.list[key]
      if (a && a.length > 0) {
        this.list[key].forEach((cb) => {
          cb(data)
        })
      }
    }
    
    // 小明订阅娱乐博主
    newsBlogger.on('娱乐博主', function (data) {
      console.log('小明您好,您接受到一条来自娱乐博主的消息' + data)
    })
    // 小张订阅体育博主
    newsBlogger.on('体育博主', function (data) {
      console.log('小张您好,您收到一条来自体育博主的消息' + data)
    })
    
    // 博主开始推送
    newsBlogger.emit('娱乐博主', '今日有新综艺更新')
    newsBlogger.emit('体育博主', '今日巴萨进行主席竞选')

如何实现移除订阅

现在由于娱乐新闻过多,推荐过于频繁,小明不想关注娱乐博主了,他该如何取消订阅呢?

   newsBlogger.remove = function (key, fn) {
    var targerList = this.list[key]
    if (targerList) {
      for (let i = 0; i < targerList.length; i++) {
        console.log(targerList[i])
        console.log(fn)
        if (targerList[i] = fn) {
          targerList.splice(i, i + 1)
        }
      }
    }
  }
  
  // 调用remove方法
  newsBlogger.remove('娱乐博主', function (data) {
    console.log('小明您好,您接受到一条来自娱乐博主的消息' + data)
  })

其他使用场景

例如vue中的EventBus,其原理就是发布-订阅模式。 可以实现子组件像父组件传递信息。