手寫實現一個簡易的發布訂閱模式,通常有以下幾個關鍵點:
-
訂閱(subscribe):用戶訂閱特定的事件,當該事件觸發時,執行與事件關聯的回調函數。
-
發布(publish):當某個事件發生時,發布該事件,并通知所有訂閱了該事件的回調函數。
發布訂閱模式實現
我們可以創建一個 EventEmitter 類,實現 subscribe、unsubscribe(取消訂閱)和 publish(發布)方法。
實現代碼:
class EventEmitter {
constructor() {
// 存儲事件名和對應的訂閱者列表
this.events = {};
}
// 訂閱事件
subscribe(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener); // 將訂閱者(回調函數)添加到事件的訂閱者列表
return () => this.unsubscribe(event, listener); // 返回取消訂閱的函數
}
// 取消訂閱
unsubscribe(event, listener) {
const listeners = this.events[event];
if (!listeners) return;
const index = listeners.indexOf(listener);
if (index !== -1) {listeners.splice(index, 1); // 移除指定的回調函數
}
}
// 發布事件
publish(event, …args) {
const listeners = this.events[event];
if (!listeners) return;
listeners.forEach(listener => listener(...args)); // 執行每個訂閱者的回調
}
}
說明:
- subscribe:
如果事件尚未存在,則為該事件創建一個空數組。
將訂閱者(即回調函數)推入事件對應的數組中。
返回一個取消訂閱的函數,方便用戶手動移除某個事件的訂閱。
- unsubscribe:
用于取消訂閱,查找指定事件的回調函數并從訂閱者列表中移除它。
- publish:
用于觸發事件,通知所有訂閱者。
通過 forEach 遍歷事件對應的回調列表,執行每個回調函數。
使用示例:
const emitter = new EventEmitter();
// 訂閱事件
const onUserLogin = (username) => {
console.log(${username} has logged in!
);
};
const onUserLogout = (username) => {
console.log(${username} has logged out!
);
};
const unsubscribeLogin = emitter.subscribe(‘login’, onUserLogin);
const unsubscribeLogout = emitter.subscribe(‘logout’, onUserLogout);
// 發布事件
emitter.publish(‘login’, ‘john_doe’); // 輸出: john_doe has logged in!
emitter.publish(‘logout’, ‘john_doe’); // 輸出: john_doe has logged out!
// 取消訂閱
unsubscribeLogin(); // 取消登錄事件的訂閱
emitter.publish(‘login’, ‘jane_doe’); // 不會輸出任何信息,因為已經取消訂閱
// 再次發布注銷事件
emitter.publish(‘logout’, ‘jane_doe’); // 輸出: jane_doe has logged out!
擴展:
如果需要支持一次性事件(例如訂閱者只想接收一次事件),可以實現一個 once 方法,訂閱后自動取消訂閱。
還可以支持事件參數的篩選、優先級等功能。
總結:
該實現提供了一個簡單的發布訂閱系統,支持事件的訂閱、取消訂閱和發布。
通過此模式,事件的發布者與訂閱者之間解耦,適合用于異步通信、消息推送、事件驅動的編程等場景。
如果你需要進一步的功能擴展或者有其他問題,隨時告訴我!