發布訂閱模式與簡單實現


發布訂閱模式與簡單實現

本文寫於 2020 年 9 月 22 日

觀察者模式(Observer Pattern)是一種設計模式,也可以叫做「發布-訂閱模式」。

等等,其實我也不清楚,通常你在網上會看到上面這一段話,但我在 Angular 文檔中讀到谷歌的說法是這樣的:觀察者模式和發布/訂閱模式非常相似(但不完全一樣)。

好吧,我們姑且就直說發布訂閱模式吧。

發布訂閱模式就像你訂了一本雜志,每當雜志新刊發布的時候,所有訂閱過雜志的人都會收到新刊一樣。

觀察者模式定義了對象之間一種 一對多 的依賴關系,每當該對象的狀態發生改變的時候,所依賴於它的其他對象都將得到通知。

在 JavaScript 中,我們會經常接觸到一個很類似的東西——事件。

事件與觀察者模式

我們先為一個 #app 元素添加兩個點擊事件:

document.querySelector('#app').addEventListener('click', () => {
  // 事件 1
});
document.querySelector('#app').addEventListener('click', () => {
  // 事件 2
});

這個時候,我們點擊 #app 元素或者使用 document.querySelector('#app').click() 或者 document.querySelector('#app').dispatchEvent('click') 來觸發時,這兩個事件都會被觸發——是不是類似與很多對象依賴於一個對象,該對象改變后所有依賴者都會被觸發。

自定義「發布-訂閱」

我們來自定義一個事件來試試。

首先我們需要一個數組儲存所有的觸發函數,這樣我們就可以對其進行遍歷,后觸發每一個事件。

const children = [];

我們還需要一個方法,來對 children 數組進行 push

const listen = (fn) => {
  children.push(fn);
}

我們再增加一個觸發函數 trigger,讓它去遍歷並觸發我們的 children

const trigger = () => {
  children.forEach((child) => {
    child();
  })
}

OK,接下來我們整合一下:

class eventHub {
  children = {}

  listen(key, fn) {
    if(this.children[key]) {
      this.children[key].push(fn);
    } else {
      this.children[key] = [fn]
    }
  }

  trigger(key) {
    this.children[key]?.forEach((child) => {
      child();
    });
  }

  remove(key, fn) {
    if(this.children[key]) {
      const children =this.children[key]
      const target = children.indexOf(fn)
      this.children[key] = [...children.slice(0, target), ...children.slice(target + 1)]
    }
  }
}

這里我們將數組換成了對象,並且為函數增加了參數,因為我們希望夠可以對多個事件進行監聽。

還添加了一個移除事件——所以我們最好使用具名函數,如果是匿名函數就無法移除監聽了!

有哪些例子?

例如一個電商網站的登陸系統,需要獲取用戶基礎信息后,獲取用戶的各項歷史記錄:

function onLogin() {
  getUserInfo()
    .then(() => {
      return getUserHistory()
    })
    .then(() => {
      getUserXXX()
    })
}

那么一旦我們需要新增一個功能,就需要在這個長函數中增加新項。

如果使用了發布-訂閱模式,就可以非常簡單的寫上新的、獨立的事件監聽了。

(完)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM