JS的釋出訂閱模式
JS的釋出訂閱模式
這裡要說明一下什麼是釋出-訂閱模式
- 釋出-訂閱模式裡面包含了三個模組,釋出者,訂閱者和處理中心。這裡處理中心相當於報刊辦事大廳。釋出者相當與某個雜誌負責人,他來中心這注冊一個的雜誌,而訂閱者相當於使用者,我在中心訂閱了這分雜誌。每當釋出者釋出了一期雜誌,辦事大廳就會通知訂閱者來拿新雜誌。這樣在結合下面的圖應該很好理解了。
- 其實就是將釋出者和訂閱者解耦了,在實際開發中,經常會遇到某個方法內處理很多的邏輯,最簡單的就是直接在方法內直接寫。這種是高度耦合的面向過程的寫法。對於程式碼維護不友好。而釋出-訂閱模式就是將兩者分離。我觸發了某個事件(這裡我們將觸發該方法定義為事件),我只向排程中心通知,我並不知道排程中心內會怎麼處理,有多少個人響應。我只管通知。而訂閱者只管在排程中心訂閱,有人呼叫它才響應。
- 還有一點就是假設我們有3個js檔案,事件觸發在a.js內,而響應該事件的在b.js和c.js內,要是用常規呼叫的方法的話,就要把b.js和c.js的方法傳到a.js內。這是一個非常麻煩的操作。而釋出-訂閱模式是將排程中心掛在了全域性,我們只管呼叫排程中心相應的方法註冊和訂閱。
ps:還有一點要注意的,很多人會把觀察者模式和釋出-訂閱模式混淆,其實兩者之間還是有點區別的,不過在本文我不會詳細講。
下面我們來實現一個釋出-訂閱模式的類
class Event { constructor () {} // 首先定義一個事件容器,用來裝事件陣列(因為訂閱者可以是多個) handlers = {} // 事件新增方法,引數有事件名和事件方法 addEventListener (type, handler) { // 首先判斷handlers內有沒有type事件容器,沒有則建立一個新陣列容器 if (!(type in this.handlers)) { this.handlers[type] = [] } // 將事件存入 this.handlers[type].push(handler) } // 觸發事件兩個引數(事件名,引數) dispatchEvent (type, ...params) { // 若沒有註冊該事件則丟擲錯誤 if (!(type in this.handlers)) { return new Error('未註冊該事件') } // 便利觸發 this.handlers[type].forEach(handler => { handler(...params) }) } // 事件移除引數(事件名,刪除的事件,若無第二個引數則刪除該事件的訂閱和釋出) removeEventListener (type, handler) { // 無效事件丟擲 if (!(type in this.handlers)) { return new Error('無效事件') } if (!handler) { // 直接移除事件 delete this.handlers[type] } else { const idx = this.handlers[type].findIndex(ele => ele === handler) // 丟擲異常事件 if (idx === undefined) { return new Error('無該繫結事件') } // 移除事件 this.handlers[type].splice(idx, 1) if (this.handlers[type].length === 0) { delete this.handlers[type] } } } }
ok到現在為止就已經實現了基本釋出訂閱的功能了,其實很簡單,如果還有什麼奇怪的需求,都可以通通往裡面加。