答案:一个高效的发布-订阅模式通过事件中心实现解耦,支持订阅、发布、取消及一次性监听。使用Object.create(null)提升性能,try-catch隔离错误,精确移除回调避免内存泄漏,适用于组件通信与状态通知场景。

实现一个高效的发布-订阅模式,关键在于轻量、解耦和性能。下面是一个简洁且实用的 JavaScript 实现,支持事件订阅、发布、取消订阅,并避免内存泄漏。
1. 基础结构:事件中心(EventEmitter)
使用一个对象存储事件类型与对应的回调函数列表,确保每个事件可以绑定多个监听器。
class PubSub {
constructor() {
this.events = Object.create(null); // 避免原型污染
}
// 订阅事件
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
// 发布事件
emit(event, data) {
if (!this.events[event]) return;
this.events[event].forEach(callback => {
try {
callback(data);
} catch (err) {
console.error(`Error in event "${event}" handler:`, err);
}
});
}
// 取消订阅
off(event, callback) {
if (!this.events[event]) return;
if (!callback) {
delete this.events[event];
return;
}
this.events[event] = this.events[event].filter(cb => cb !== callback);
}
}
2. 提升效率的关键点
为了让 Pub/Sub 更高效,注意以下几点:
- 使用 Object.create(null):避免原型链干扰,提升查找性能。
- 错误隔离:在 emit 中用 try-catch 包裹回调,防止一个回调出错影响其他监听器。
- 支持取消特定监听器:允许传入具体 callback 来精确移除。
- 批量清除:不传 callback 调用 off 时清空整个事件队列,便于资源回收。
3. 使用示例
这个模式非常适合组件通信、状态更新通知等场景。
立即学习“Java免费学习笔记(深入)”;
const bus = new PubSub();
// 订阅消息
bus.on('userLogin', user => {
console.log('欢迎用户:', user.name);
});
bus.on('userLogin', () => {
console.log('更新登录状态');
});
// 发布消息
bus.emit('userLogin', { name: 'Alice' });
// 取消某个订阅
const welcomeHandler = user => console.log('打招呼:', user.name);
bus.on('userLogin', welcomeHandler);
bus.off('userLogin', welcomeHandler); // 移除该监听
4. 可选优化:支持只监听一次
添加 once 方法,在回调执行后自动取消订阅。
once(event, callback) {
const wrapped = (...args) => {
callback.apply(this, args);
this.off(event, wrapped);
};
this.on(event, wrapped);
}










