发布订阅模式(Pub/Sub)是前端和后端都非常常见的一种设计模式,本质是解耦:
- 发布者(Publisher)发消息
- 订阅者(Subscriber)接收消息
- 中间通过一个“事件中心”来管理
🧠 一、核心思想
可以把它理解成:
“我不关心谁在听,只负责发;你不关心谁在发,只负责订阅。”
典型结构:
on:订阅事件emit:发布事件off:取消订阅
💻 二、手写一个发布订阅(JS实现)
这是最经典、面试也最常考的实现👇
class EventBus {
constructor() {
this.events = {};
}
// 订阅
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
}
// 发布
emit(eventName, ...args) {
const handlers = this.events[eventName];
if (handlers) {
handlers.forEach(fn => fn(...args));
}
}
// 取消订阅
off(eventName, callback) {
const handlers = this.events[eventName];
if (!handlers) return;
this.events[eventName] = handlers.filter(fn => fn !== callback);
}
// 只执行一次
once(eventName, callback) {
const fn = (...args) => {
callback(...args);
this.off(eventName, fn);
};
this.on(eventName, fn);
}
}
🚀 三、使用示例
const bus = new EventBus();
// 订阅
const handler = (msg) => {
console.log('收到消息:', msg);
};
bus.on('test', handler);
// 发布
bus.emit('test', 'hello world');
// 取消订阅
bus.off('test', handler);
// 只执行一次
bus.once('onceEvent', (msg) => {
console.log('只执行一次:', msg);
});
bus.emit('onceEvent', '第一次');
bus.emit('onceEvent', '第二次'); // 不会触发
⚔️ 四、和观察者模式的区别(面试重点)
很多人会混,这里帮你理清:
| 对比点 | 发布订阅 | 观察者模式 |
|---|---|---|
| 中间层 | ✅ 有(EventBus) | ❌ 没有 |
| 耦合度 | 低 | 高 |
| 关系 | 松散 | 直接依赖 |
| 使用场景 | Vue事件、消息系统 | 响应式数据 |
👉 一句话总结:
发布订阅 = 多加了一层“中介”,更解耦
🧩 五、前端实际应用场景
你项目里其实已经可能用过👇
1️⃣ Vue / React 事件通信
// mitt / eventemitter3 本质就是 pub/sub
2️⃣ 跨组件通信(非父子)
- EventBus
- 全局状态管理(Redux 本质也有类似思想)
3️⃣ WebSocket 消息分发
socket.onmessage = (msg) => {
eventBus.emit(msg.type, msg.data);
};
4️⃣ 你之前做的性能平台(很适合用)
比如:
- 图表联动(ECharts)
- 筛选条件同步
- 多模块刷新
🔥 六、进阶优化(高级面试点)
你可以再升级一下👇
✅ 1. 支持事件命名空间
"user:login"
"user:logout"
✅ 2. 支持通配符
"user:*"
✅ 3. 异步发布(Promise)
emit async
✅ 4. 防止重复订阅
Set 替代 Array
🧭 七、一句话总结
发布订阅模式 = “事件中心 + 松耦合通信”,是大型前端架构必备能力