EventBus
EventBus 是一种通信机制,基于发布订阅设计模式。它可以在不同模块/组件之间进行通信。
实现
核心理念是,在任一程序中发布某一事件,其它订阅了该事件的模块会收到通知,执行绑定的监听器。
js
class EventBus {
#eventBus = Object.create(null)
/**
* 触发一个事件
* @param {String} eventName 事件名称
* @param {...any} args 参数
*/
emit(eventName, ...args) {
if (!this.#eventBus[eventName]?.length) return
for (const listener of this.#eventBus[eventName]) {
listener(...args)
}
}
/**
* 为某个事件绑定监听器
* @param {String} eventName 事件名称
* @param {Function} listener 事件监听器
*/
on(eventName, listener) {
if (!this.#eventBus[eventName]) this.#eventBus[eventName] = []
this.#eventBus[eventName].push(listener)
}
/**
* 移除事件监听器
* @param {String} eventName 事件名称
* @param {Function} [listener] 事件监听器,不传移除 eventName 绑定的所有监听器
*/
off(eventName, listener) {
if (!this.#eventBus[eventName]?.length) return
if (!listener) {
delete this.#eventBus[eventName]
} else {
const index = this.#eventBus[eventName].indexOf(listener)
index !== -1 && this.#eventBus[eventName].splice(index, 1)
}
}
}#eventBus:事件存储器,用于管理事件及监听器。on:针对某个事件添加监听器,在收到发布时执行绑定的监听器。emit:发布事件,发布后会执行 #eventBus 中订阅该事件的监听器。off:移除事件监听。
扩展
以上代码即可实现一个事件总线程序,实际开发可以添加额外功能,以获得更好的体验
- 错误处理:在循环调用监听器列表时,进行错误捕获,避免因单个监听器的错误导致后续监听器无法执行。js
emit(eventName, ...args) { if (!this.#eventBus[eventName]?.length) return for (const listener of this.#eventBus[eventName]) { try { listener(...args) } catch(error) { console.error(`Error in event handler for ${eventName}:`, error) } } } - 仅执行一次的监听器:可以添加 once 方法,用于注册只触发一次的事件监听器。js
once(eventName, listener) { const onceListener = (...args) => { this.off(eventName, onceListener) listener(...args) } this.on(eventName, onceListener) } - 性能优化:#eventBus 可以使用 Map 结构,对应的事件监听器列表可以使用 Set 结构,在大量的事件和监听器中,提高性能。
