发布订阅模式:JavaScript世界里的「微信公众号」

66 阅读4分钟

大家好,我是前端老司机,今天要聊的是设计模式中的「微信公众号」——发布订阅模式。这不是什么高大上的技术,而是让代码更灵活、更解耦的实用技巧。

发布订阅模式是个啥?

简单来说,发布订阅模式就是:一个主题对象状态改变时,能通知所有订阅了它的观察者对象。就像微信公众号一样,博主发文章(发布事件),所有关注的粉丝(订阅者)都会收到推送(执行相应操作)。

最重要的一点是:发布者不直接接触订阅者,而是通过一个第三方(事件中心)来通信。这就像公众号平台一样,博主和粉丝之间没有直接联系,但通过平台可以实现信息的传递。

从代码看发布订阅模式的实现

让我们来看一个典型的发布订阅模式实现:

class EventEmitter {
  constructor() {
    this.eventList = {
      // 'hasHouse': [kang, wrap],
      // 'hasCar': [cheng]
    }
  }

  on(eventName, cb) {  // 订阅
    if (!this.eventList[eventName]) {
      this.eventList[eventName] = []
    }
    this.eventList[eventName].push(cb)
  }
  
  emit(eventName) {  // 发布
    if (this.eventList[eventName]) {
      const handlers = this.eventList[eventName].slice()
      handlers.forEach((item) => {
        item()
      })
    }
  }
  
  off(eventName, cb) {  // 取消订阅
    const callbacks = this.eventList[eventName]
    const index = callbacks.indexOf(cb)
    if (index !== -1) {
      callbacks.splice(index, 1)
    }
  }
  
  once(eventName, cb) {  // 订阅一次
    const wrap = () => {
      cb()
      this.off(eventName, wrap)
    }
    this.on(eventName, wrap)
  }
}

这个 EventEmitter 类就是我们的「公众号平台」,它提供了四个核心方法:

  1. on: 订阅事件(关注公众号)
  2. emit: 发布事件(推送文章)
  3. off: 取消订阅(取消关注)
  4. once: 订阅一次事件(一次性推送)

发布订阅模式的「实战演练」

让我们用一个生活中的例子来演示如何使用发布订阅模式:

// 创建事件中心(公众号平台)
let _event = new EventEmitter() 

// 定义订阅者(粉丝)
function kang() {  // 康总
  console.log('康总买房')
}
function ji() {  // 老骥
  console.log('老骥买房');
}
function cheng() {  // 成哥
  console.log('成哥买车位');
}

// 订阅事件(关注公众号)
_event.on('hasHouse', kang)  // 康总关注了「有房了」公众号
_event.once('hasHouse', ji)  // 老骥只关注一次「有房了」公众号
_event.on('hasCar', cheng)  // 成哥关注了「有车了」公众号

// 发布事件(推送文章)
_event.emit('hasHouse')  // 「有房了」公众号推送了文章
// 输出:
// 康总买房
// 老骥买房

_event.emit('hasHouse')  // 「有房了」公众号再次推送文章
// 输出:
// 康总买房
// (老骥因为只订阅一次,所以第二次没收到)

这个例子完美诠释了发布订阅模式的工作原理:当某个事件(有房了)发生时,所有订阅了这个事件的函数都会被调用。而且,通过 once 方法,我们还实现了只订阅一次的功能。

发布订阅 vs 观察者:傻傻分不清?

很多人会把发布订阅模式和观察者模式搞混,其实它们有一个关键区别:

  • 发布订阅模式:发布者和订阅者之间有一个第三方(事件中心),它们不直接接触
  • 观察者模式:发布者(被观察者)直接接触订阅者(观察者)

就像:

  • 发布订阅模式 = 微信公众号(平台)+ 博主 + 粉丝
  • 观察者模式 = 直销员 + 客户(直销员直接联系客户)

发布订阅模式的「高光时刻」

发布订阅模式在前端开发中简直是「香饽饽」,它的应用场景无处不在:

  1. DOM 事件监听document.addEventListener('click', handler) 就是典型的发布订阅模式
  2. Vue/React 等框架的事件系统:组件间通信经常用到发布订阅模式
  3. Redux/Vuex 等状态管理库:状态变化时通知组件更新
  4. Node.js 的 EventEmitter:Node.js 核心模块,广泛用于各种事件处理

写在最后

发布订阅模式就像 JavaScript 世界里的「微信公众号」,它让代码之间的通信变得更加灵活、解耦。通过一个第三方的事件中心,发布者和订阅者可以互不相识,但依然能够完美协作。

下次写代码时,如果你发现多个组件或模块之间需要通信,但又不想让它们直接耦合,不妨试试发布订阅模式,让你的代码像微信公众号一样高效运作!

你在项目中用过发布订阅模式吗?欢迎在评论区分享你的使用经验~