文章中英模式
布魯斯前端JS面試題目 - 實作訂閱與發佈模式
學習如何實作 JavaScript 中的訂閱與發佈(Subscribe & Emit)模式,掌握事件驅動程式設計的核心概念,提升前端程式碼的解耦與可維護性。
文章中英模式
懶得看文章?那就來看影片吧
訂閱與發佈模式概述
訂閱與發佈模式(Pub/Sub Pattern)是一種常見的設計模式,它允許不同組件之間透過事件機制進行通信,而不需要彼此之間直接引用。這種模式能夠降低組件間的耦合度,提高程式碼的可維護性和可擴展性。
核心概念
- 1. 發布者(Publisher/Emitter):負責發出事件的對象
- 2. 訂閱者(Subscriber/Listener):監聽並響應事件的對象
- 3. 事件(Event):由發布者發出的訊息,通常包含事件名稱和相關數據
- 4. 事件總線(Event Bus):負責管理訂閱關係和分發事件的中間層
JavaScript 生態系統中廣泛使用此模式,比如 DOM 事件、Node.js 的 EventEmitter、Vue 的事件系統等。
基本的 EventEmitter 實作
下面是一個簡單的 EventEmitter 實作,包含最基本的訂閱(on/subscribe)和發佈(emit)功能:
class EventEmitter {
constructor() {
// 存儲事件與對應的監聽器
this.events = {};
}
// 訂閱事件
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
return this; // 支持鏈式調用
}
// 發布事件
emit(event, ...args) {
const listeners = this.events[event];
if (!listeners || listeners.length === 0) {
return false;
}
listeners.forEach(listener => {
listener.apply(this, args);
});
return true;
}
}
// 使用範例
const emitter = new EventEmitter();
// 訂閱事件
emitter.on('userLoggedIn', user => {
console.log(`用戶 ${user.name} 已登入`);
});
emitter.on('userLoggedIn', user => {
updateUIForLoggedInUser(user);
});
// 發布事件
emitter.emit('userLoggedIn', { name: 'John', id: 123 });
// 輸出: 用戶 John 已登入
實際應用場景
以下是兩個訂閱與發佈模式的簡單應用示例:
1. 簡單的通知系統
// 建立事件管理器
const notifier = new EventEmitter();
// 訂閱不同類型的通知
notifier.on('message', data => {
console.log(`收到訊息: ${data.text}`);
showNotification(data.text);
});
notifier.on('error', data => {
console.error(`錯誤: ${data.message}`);
showErrorAlert(data.message);
});
// 在應用程式中發送通知
function sendMessage(text) {
notifier.emit('message', { text, time: new Date() });
}
function reportError(message) {
notifier.emit('error', { message, code: 500 });
}
// 使用範例
sendMessage('歡迎使用本系統');
reportError('連線失敗');
2. 簡易狀態管理
// 簡單的狀態管理器
const store = new EventEmitter();
const state = { count: 0, user: null };
// 訂閱狀態變化
store.on('stateChange', (newState) => {
console.log('狀態已更新:', newState);
renderUI(newState);
});
// 更新狀態的方法
function updateState(changes) {
Object.assign(state, changes);
store.emit('stateChange', state);
}
// 使用範例
function increment() {
updateState({ count: state.count + 1 });
}
function login(user) {
updateState({ user });
}
// 觸發狀態變化
increment(); // 狀態已更新: { count: 1, user: null }
login({ name: 'Alice' }); // 狀態已更新: { count: 1, user: { name: 'Alice' } }