简单的事件总线/发布订阅模式

Published on
Published on
/4 mins read/---

简单的事件总线或发布订阅模式

event-emitter.js
class Event {
  constructor() {
    this.events = {}
  }
 
  subscribe(event, handler) {
    this.events[event] = this.events[event] || []
    this.events[event].push(handler)
    return () => this.unSubscribe(event, handler)
  }
 
  unSubscribe(event, handler) {
    let handlers = this.events[event]
    if (handlers && Array.isArray(handlers)) {
      for (let i = 0; i < handlers.length; i++) {
        if (handlers[i] === handler) {
          handlers.splice(i, 1)
          break
        }
      }
    }
  }
 
  emit(event, ...args) {
    ;(this.events[event] || []).forEach((handler) => {
      handler(...args)
    })
  }
}

使用方法

main.js
// 在你的应用中创建一个全局实例
let globalEvent = new Event()
 
let handler1 = (data) => console.log(`handler1(): FOO事件触发,数据: ${data}`)
let handler2 = (data) => console.log(`handler2(): FOO事件触发,数据: ${data}`)
 
// 订阅事件
globalEvent.subscribe('FOO', handler1)
globalEvent.subscribe('FOO', handler2)
 
// 在需要时触发事件
globalEvent.emit('FOO', 'foo')
 
// 预期输出:
// handler1(): FOO事件触发,数据: foo
// handler2(): FOO事件触发,数据: foo
 
// 取消订阅事件
globalEvent.unSubscribe('FOO', handler2)
 
// 然后
globalEvent.emit('FOO', 'bar')
 
// 预期输出:
// handler1(): FOO事件触发,数据: bar

高级功能

一次性订阅

添加只执行一次的事件订阅:

event-emitter-advanced.js
class EventEmitter {
  constructor() {
    this.events = {}
  }
 
  subscribe(event, handler) {
    this.events[event] = this.events[event] || []
    this.events[event].push(handler)
    // 返回取消订阅函数
    return () => this.unSubscribe(event, handler)
  }
 
  // 一次性订阅
  once(event, handler) {
    const onceHandler = (...args) => {
      handler(...args)
      this.unSubscribe(event, onceHandler)
    }
    return this.subscribe(event, onceHandler)
  }
 
  unSubscribe(event, handler) {
    let handlers = this.events[event]
    if (handlers && Array.isArray(handlers)) {
      for (let i = 0; i < handlers.length; i++) {
        if (handlers[i] === handler) {
          handlers.splice(i, 1)
          break
        }
      }
    }
  }
 
  // 清除所有事件监听器
  clear(event) {
    if (event) {
      delete this.events[event]
    } else {
      this.events = {}
    }
  }
 
  emit(event, ...args) {
    ;(this.events[event] || []).forEach((handler) => {
      try {
        handler(...args)
      } catch (error) {
        console.error(`事件处理器错误:`, error)
      }
    })
  }
 
  // 获取事件的监听器数量
  listenerCount(event) {
    return (this.events[event] || []).length
  }
}

使用示例

usage-examples.js
const eventBus = new EventEmitter()
 
// 基础订阅
const unsubscribe = eventBus.subscribe('user-login', (user) => {
  console.log(`用户 ${user.name} 已登录`)
})
 
// 一次性订阅
eventBus.once('app-ready', () => {
  console.log('应用初始化完成')
})
 
// 触发事件
eventBus.emit('user-login', { name: 'John', id: 123 })
eventBus.emit('app-ready')
 
// 取消订阅
unsubscribe()
 
// 查看监听器数量
console.log(eventBus.listenerCount('user-login')) // 0

实际应用场景

组件通信

// 在React或Vue组件中使用
class ComponentA {
  constructor() {
    this.eventBus = globalEvent
  }
 
  sendMessage() {
    this.eventBus.emit('message', '来自组件A的消息')
  }
}
 
class ComponentB {
  constructor() {
    this.eventBus = globalEvent
    this.eventBus.subscribe('message', this.handleMessage.bind(this))
  }
 
  handleMessage(message) {
    console.log('组件B收到消息:', message)
  }
}

状态管理

// 简单的状态管理
class SimpleStore {
  constructor() {
    this.state = {}
    this.events = new EventEmitter()
  }
 
  setState(newState) {
    this.state = { ...this.state, ...newState }
    this.events.emit('state-change', this.state)
  }
 
  subscribe(callback) {
    return this.events.subscribe('state-change', callback)
  }
}

优势

  • 轻量级: 无需外部依赖
  • 简单易用: API清晰直观
  • 解耦: 组件间松耦合通信
  • 灵活: 支持多个监听器和参数传递

注意事项

  • 避免内存泄漏:记得取消不需要的订阅
  • 错误处理:在事件处理器中添加错误处理
  • 命名规范:使用清晰的事件名称
  • 调试支持:可以添加调试日志功能