簡介 發佈訂閱模式是一種常用的用於解耦的模式。 它和觀察者模式的區別在於: 觀察者模式:被觀察者需要維護一個觀察者的集合; 發佈訂閱模式:通信雙方互相不知道對方的存在,通過第三方事件匯流排進行通信。 發佈訂閱模式在前端領域很常見,例如: Vue 框架中組件的$on和$emit方法; Node.js 中 ...
簡介
發佈訂閱模式是一種常用的用於解耦的模式。
它和觀察者模式的區別在於:
- 觀察者模式:被觀察者需要維護一個觀察者的集合;
- 發佈訂閱模式:通信雙方互相不知道對方的存在,通過第三方事件匯流排進行通信。
發佈訂閱模式在前端領域很常見,例如:
- Vue 框架中組件的
$on
和$emit
方法; - Node.js 中 EventEmitter 中的
on
和emit
方法。
圖示:
-
訂閱者通過
on
方法註冊事件: -
發佈者通過
emit
觸發回調列表:發佈者和訂閱者雙方不知道各自的存在,它們僅通過
Event Bus
進行通信。
實現
事件匯流排最基本的兩個方法是 on
和 emit
。
常見的設計還有兩個方法是 off
和 once
,off
用於註銷事件,once
是 on
的特例,表示僅訂閱一次。
函數簽名
type CallbackFn = (...args: any[]) => void;
on(eventName: string, callback: CallbackFn): void;
emit(enentName: string, ...args: any): void;
off(eventName: string, callback: CallbackFn): void;
once(eventName: string, callback: CallbackFn): void;
實現思路
在事件匯流排中需要建立起事件名到回調集合的映射:
- 當
on
時,將回調添加到指定事件名的回調集合中; - 當
emit
時,遍歷指定時間名的回調集合,依次執行其中的回調函數;
回調集合可以使用Set
實現,也可以使用數組實現。
由於on
的實現需要做去重,建議使用Set,比較方便。
once的實現:
once 可以基於 on 和 off 實現,先使用 on 註冊,執行回調之後就執行 off 註銷,從而實現僅觸發一次。
代碼
使用 TypeScript 實現。
首先聲明一個回調函數的類型,簡化後續代碼:
type CallbackFn = (...args: any[]) => void;
然後是聲明 EventBus 類,成員屬性中使用對象建立起 “事件名與回調集合” 的映射關係:
class EventBus{
events: Record<string, Set<CallbackFn>> = {};
constructor(){}
on(eventName: string, callback: CallbackFn){ /* ... */ }
emit(eventName: string, ...args: any[]){/* ... */}
off(eventName: string, callback: CallbackFn){/* ... */}
once(eventName: string, callback: CallbackFn){/* ... */}
}
on
on(eventName: string, callback: CallbackFn){
if(!this.events[eventName]){
this.events[eventName] = new Set();
}
this.events[eventName].add(callback);
}
- 如果事件名不存在,則要初始化創建一個 Set 用於記錄。
- 如果事件名存在,則直接將回調添加到 Set 中。
這段代碼可以通過 短路運算符 簡化:
on(eventName: string, callback: CallbackFn){
(this.events[eventName] ??= new Set()).add(callback);
}
emit
遍歷回調集合就