JavaScript观察者模式

本文深入探讨了发布订阅模式,一种广泛应用于异步编程中的设计模式。详细解释了其原理,如何替代回调函数,并展示了实现过程,包括基本模式、改进版及通用应用方式,使对象间通讯更灵活、解耦。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、发布订阅模式定义

发布订阅模式也叫观察者模式,它定义了对象中一种一对多的依赖关系,当对象的一个状态发生改变时,所有依赖于它的对象都将得到通知

发布订阅模式可以广泛的运用在异步编程中,可以取代回掉函数,比如我们可以监听Ajax的error和success事件。或者我们想在动画完成每一帧后执行一些事件,那我们可以订阅这个事件,在动画每一帧结束后发布这个事件,在异步编程中使用发布于订阅模式,我们不必过多关心对象在异步期间的状态,而只需订阅感兴趣的事件发生点。

发布订阅模式可以取代对象之间硬编码的通知机制,一个对象不再显示的调用另外一个对象的接口。发布订阅模式将两个对象松耦合的联系在一起,它们不必清除的知道对方的细节。当有新的订阅者出现时,发布者不需要做任何修改,也不会影响到之前的订阅者,只要事先约定的事件名没有发生变化,就可以自由地改变他们。

2、实现发布订阅

  1. 首先指定发布者
  2. 然后给发布者添加一个缓存列表,用于存放回掉函数,以便通知订阅者
  3. 在发布消息的时候遍历这个缓存列表,触发订阅者的回调函数
let publisher = {} // 发布者
publisher.clientList = [] // 缓存列表,用于存放订阅者的回调函数
publisher.listen = function (fn) {
  this.clientList.push(fn)
}
publisher.trigger = function () {
  for (let i = 0; i < this.clientList.length; i++) {
    const fn = this.clientList[i]
    fn.apply(this, arguments)
  }
  // for(let i = 0, fn; fn = )
}
publisher.listen(function (price, data) {
  console.log(price)
  console.log(data)
})
publisher.listen(function (price, data) {
  console.log(price)
  console.log(data)
})
publisher.trigger(20000, 183)

这样的发布订阅模式存在一个问题,即所有订阅者都会接收到相同的消息,即使订阅者对此类消息不感兴趣。

改进:

let publisher = {}
publisher.clientList = {}
publisher.listen = function (key, fn) { // key表示订阅者想要接收消息的关键字
  if (!this.clientList[key]) {
    this.clientList[key] = []
  }
  this.clientList[key].push(fn)
}
publisher.trigger = function () {
  let key = [].shift.call(arguments)
  let fns = this.clientList[key]
  if (!fns || fns.length == 0) {
    return false
  }
  for(let i = 0, fn; fn = fns[i++];) {
    fn.apply(this, arguments)
  }
}

publisher.listen('88', function (price, data) { // 该订阅者只接受key为88的消息
  console.log('88',price)
  console.log(data)
})
publisher.listen('100', function (price, data) {
  console.log(price)
  console.log(data)
})
publisher.trigger('88', 20000, 183) // 发布key为88的消息

3、通用的发布订阅模式

在上面我们只针对某一个具体的对象添加了发布订阅模式,如果我们想要为其他对象添加发布订阅模式就需要把这样的代码再重新写一次,为了降低代码的耦合性,我们把发布订阅的功能抽取出来,封装为一个对象,然后通过某个方法把发布订阅模式的功能添加到我们想要的对象上,这样就降低了代码的耦合性。

// 首先抽取发布订阅的功能
let event = {
  clientList: {},
  listen: function (key, fn) {
    if (!this.clientList[key]) {
      this.clientList[key] = []
    }
    this.clientList[key].push(fn)
  },
  trigger: function () {
    let key = [].shift.call(arguments)
    let fns = this.clientList[key]

    if (!fns || fns.length == 0) {
      return false
    }

    for(let i = 0, fn; fn = fns[i++];) {
      fn.apply(this, arguments)
    }
  }
}
// 定义一个函数,给对象绑定发布订阅模式
let installEvent = function (obj) {
  for (const i in event) {
    if (event.hasOwnProperty(i)) {
      obj[i] = event[i]
    }
  }
}
// 使用
let publisher = {}
installEvent(publisher)
publisher.listen('88', function (price, data) {
  console.log('88',price)
  console.log(data)
})
publisher.listen('100', function (price, data) {
  console.log(price)
  console.log(data)
})
publisher.trigger('88', 20000, 183)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值