JS設計模式(5): 發布訂閱模式

解鎖JavaScript發布訂閱模式:讓代碼溝通更優雅

在JavaScript的世界里,我們常常會遇到這樣的場景:多個模塊之間需要相互通信,但是又不想讓它們產生過于緊密的耦合。這時候,發布訂閱模式就像一位優雅的信使,能夠幫助我們實現模塊間的解耦,讓代碼的結構更加清晰、可維護。今天,我們就來深入探討一下JavaScript中的發布訂閱模式,并用一段代碼來揭開它的神秘面紗。

什么是發布訂閱模式?

發布訂閱模式(Publish/Subscribe Pattern)是一種消息范式,發布者(Publisher)不會將消息直接發送給特定的訂閱者(Subscriber),而是將發布的消息分為不同的類別,無需了解哪些訂閱者(如果有的話)可能存在。同樣的,訂閱者可以表達對一個或多個類別的興趣,只接收感興趣的消息,無需了解哪些發布者(如果有的話)存在。這種模式實現了發布者和訂閱者之間的解耦,使得它們可以獨立變化而互不影響。

在JavaScript的編程場景中,比如我們開發一個復雜的Web應用,有多個組件需要響應某個事件的變化,例如用戶登錄狀態的改變、數據的更新等。如果采用傳統的方式,組件之間可能需要相互引用、層層調用,這會導致代碼的耦合度極高,后期維護和擴展都非常困難。而發布訂閱模式則提供了一種更好的解決方案,它允許組件之間通過事件進行通信,組件只需要關心自己感興趣的事件,而無需了解事件的來源和其他組件的內部實現。

發布訂閱模式的實現

下面,我們通過一段代碼來實現一個簡單的發布訂閱模式。我們創建一個EventEmitter類,它將作為我們的事件發射器,負責管理事件的訂閱、發布和取消訂閱等操作。

class EventEmitter {constructor () {this.event = {}}// 訂閱事件on (eventName, callback) {if (!this.event[eventName]) {this.event[eventName] = []}this.event[eventName].push(callback)return this}// 發布事件emit (eventName, ...args) {if (this.event[eventName]) {this.event[eventName].forEach(callback => callback(...args))}return this}// 取消訂閱off (eventName, callback) {if (this.event[eventName]) {this.event[eventName] = this.event[eventName].filter(cb => cb!== callback)}return this}// 單次訂閱once (eventName, callback) {const wrapper = (...args) => {callback(...args)this.off(eventName, wrapper)}this.on(eventName, wrapper)}
}

在上述代碼中,EventEmitter類的構造函數初始化了一個空對象event,用于存儲不同事件名稱對應的回調函數數組。on方法用于訂閱事件,它會將傳入的回調函數添加到對應事件名稱的數組中。emit方法用于發布事件,當調用emit時,它會查找對應事件名稱的回調函數數組,并依次執行數組中的每個回調函數,同時將傳入的參數傳遞給回調函數。off方法用于取消訂閱,它會從對應事件名稱的回調函數數組中過濾掉指定的回調函數。once方法用于實現單次訂閱,即回調函數只會執行一次,執行完畢后會自動取消訂閱。

發布訂閱模式的實際應用示例

為了更好地理解發布訂閱模式的實際應用,我們來看一個具體的例子。假設我們有一個表示人的對象person,我們想要在其age屬性發生變化時,通知其他相關的對象進行相應的處理。我們可以使用Proxy結合發布訂閱模式來實現這個功能。

const eventBus = new EventEmitter()const obj = {age: 21,onAgeChange: function (newAge) {this.age = newAgeconsole.log('age 發生改變,現在是', this.age)}
}const person = {age: 10,
}const proxyPerson = new Proxy(person, {set: (target, key, newValue) => {eventBus.emit(`${key}Change`, newValue)}
})eventBus.on('ageChange', obj.onAgeChange)proxyPerson.age = 20
proxyPerson.age = 100

在這個例子中,我們首先創建了一個EventEmitter實例eventBus作為事件總線。然后,我們定義了一個obj對象,它包含一個age屬性和一個onAgeChange方法,用于處理age屬性變化的邏輯。接著,我們創建了一個person對象,并使用Proxy對其進行代理。在Proxyset方法中,當person對象的屬性發生變化時,我們通過eventBus發布一個ageChange事件,并將新的值作為參數傳遞出去。最后,我們通過eventBuson方法將objonAgeChange方法訂閱到ageChange事件上。當我們修改proxyPersonage屬性時,就會觸發ageChange事件,objonAgeChange方法也會被調用,從而實現了age屬性變化的通知和處理。

發布訂閱模式的優勢與注意事項

優勢

  1. 解耦:發布者和訂閱者之間沒有直接的依賴關系,它們只通過事件進行通信。這樣,當我們需要添加、刪除或修改某個組件時,不會影響到其他組件,大大提高了代碼的可維護性和擴展性。
  2. 靈活性:可以很方便地添加新的訂閱者或發布者,而不需要修改已有的代碼。例如,在我們的例子中,如果后續還有其他對象需要響應age屬性的變化,只需要通過eventBus訂閱ageChange事件即可。
  3. 可復用性EventEmitter類可以在多個項目或模塊中復用,減少了重復代碼的編寫。

注意事項

  1. 內存管理:如果訂閱者訂閱了大量的事件,并且沒有及時取消訂閱,可能會導致內存泄漏。因此,在使用發布訂閱模式時,一定要注意及時取消不再需要的訂閱。
  2. 調試困難:由于事件的發布和訂閱是異步進行的,而且可能涉及多個組件之間的通信,所以在調試時可能會比較困難。我們可以通過添加日志輸出等方式來輔助調試。

總結

發布訂閱模式是JavaScript中一種非常實用的設計模式,它通過解耦組件之間的通信,讓我們的代碼更加靈活、可維護和可擴展。通過本文的介紹和示例,相信你對發布訂閱模式已經有了更深入的理解。在今后的JavaScript開發中,不妨嘗試運用發布訂閱模式,讓你的代碼溝通更加優雅!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/86619.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/86619.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/86619.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【電路物聯網】SDN架構與工作原理介紹

(??? ),Hello我是祐言QAQ我的博客主頁:C/C語言,數據結構,Linux基礎,ARM開發板,網絡編程等領域UP🌍快上🚘,一起學習,讓我們成為一個強大的攻城獅&#xff0…

vscode 保存 js 時會自動格式化,取消設置也不好使

vscode 里的設置搜索 Editor: Format On Save 取消勾選 卸載 Prettier - Code formatter 這個插件后好使了,本來以為是插件的問題,后來發現是工作區設置的問題。 因為我是用 GitHub 下載的工程打開后, vscode 認為是工作區了, 因為 .vscode…

xcode中project.pbxproj點開為空白問題

由于需要修改signing里面的配置,點擊了project.pbxproj。但是發現一片空白,如圖 以為是配置文件損壞,郵件show in Finder看了一通后沒看出什么所以然。并且發現entitlement文件、list文件全都是點開為白,并且沒有任何保存 最后發…

JUC并發編程(四)常見模式

目錄 一 同步與協調模式 1 保護性暫停模式 2 順序控制模式 3 生產者消費者模式 4 Balking模式(猶豫模式) 二 線程管理/生命周期模式 1 兩階段終止模式 一 同步與協調模式 1 保護性暫停模式 一個線程需要等待另一個線程提供特定條件(通常是…

Vue 數據代理機制對屬性名的要求

Vue 數據代理機制對屬性名的要求 在 Vue 的數據代理機制中,屬性名需遵循以下關鍵規則: 1. 禁止以 _ 或 $ 開頭 ?? Vue 會跳過代理以 _ 或 $ 開頭的屬性原因:這些前綴被 Vue 保留用于內部屬性(如 _data, _uid, $refs, $el 等)示例:data() {return {count: 1, // ?…

pdf.js在iOS移動端分頁加載優化方案(ios移動端反復刷新加載問題)

背景與問題 在iOS移動端加載大型PDF文件時,由于設備內存限制,經常遇到以下問題: 內存不足導致頁面崩潰大文件加載緩慢頁面反復重新加載 ##解決方案 采用PDF.js的分頁加載策略,實現按需加載當前可視頁面及相鄰頁面,…

【C++】來學習使用set和map吧

各位大佬好,我是落羽!一個堅持不斷學習進步的大學生。 如果您覺得我的文章有所幫助,歡迎多多互三分享交流,一起學習進步! 也歡迎關注我的blog主頁: 落羽的落羽 文章目錄 一、set和map是什么二、set系列1. set2. mult…

h5st逆向分析

h5st最新5.1版本逆向分析 申明定位h5st生成的位置動態插樁,事半功倍日志分析,十分鐘還原算法邏輯申明 本文僅用來記錄學習過程以免日后忘了,如有侵權請聯系刪除。 定位h5st生成的位置 通過關鍵字“sign”搜索,可以定位到window.PSign.sign(f)這個位置,f參數的值為{ &qu…

湖北理元理律師事務所企業債務優化路徑:司法重整中的再生之道

一、企業債務危機的核心矛盾:生存與清償的博弈 通過分析湖北理元理律師事務所經辦的17件企業債務案件,發現共性難題: 債權人要求立即清償 → 企業需持續經營造血 → 司法程序存在時間差 解決方案:構建“三重防火墻”機制 經…

鏈家Android面試題及參考答案

目錄 請詳細解釋類加載的過程,包括每一步的具體實現。并說明Android中的dex分包技術及其在熱更新中的應用 比較JVM和DVM的區別。在JVM中一個程序崩潰是否可能導致系統崩潰?DVM中呢? 請解釋網絡IP協議、TCP、UDP、HTTP、HTTPS、Socket的概念,并說明它們之間的區別 請深入…

LeetCode-多語言實現冒泡排序以及算法優化改進

目錄 一、冒泡排序算法 二、應用場景/前提條件 🌈 優點 📢 缺點 三、經典算法實現并優化改進 方法一:記錄最后一次交換位置,下一輪只遍歷到該位置 方法二:添加標志位跟蹤是否發生交換,無交換則提前終…

JAVA畢業設計227—基于SpringBoot+hadoop+spark+Vue的大數據房屋維修系統(源代碼+數據庫)

畢設所有選題: https://blog.csdn.net/2303_76227485/article/details/131104075 基于SpringBoothadoopsparkVue的大數據房屋維修系統(源代碼數據庫)227 一、系統介紹 本項目前后端分離,分為業主、維修人員、管理員三種角色 1、業主: 登…

MADlib —— 基于 SQL 的數據挖掘解決方案(9)—— 數據探索之概率統計

目錄 一、概率 1. 概率的定義 2. 概率質量函數與概率密度函數 3. 條件概率 4. 期望值 二、MADlib 的概率相關函數 1. 函數語法 2. 示例 (1)求標準正態分布下,1 的概率密度函數 (2)求標準正態分布下&#xff…

耳蝸里的春天

早春的鄭州飄著細雨,我牽著女兒小滿的手走進市殘疾人康復中心時,玻璃門內突然傳來一陣清脆的笑聲。穿天藍色毛衣的小女孩戴著粉色耳蝸,正踮腳拍打著墻上的卡通貼畫,銀色的連接線在她耳后晃動,像一只折翼卻仍在起舞的蝴…

OCR(光學字符識別)算法

OCR(光學字符識別)算法在景區護照閱讀器中的應用是核心技術之一,它通過圖像處理和機器學習快速提取護照信息,顯著提升自動化水平。以下是其具體應用場景、技術實現及優化方向: 一、OCR在護照閱讀器中的核心作用 關鍵信…

html打印合同模板

概述(吐槽):記錄一個html打印合同模板的功能,技術棧有點雜,千禧年出產老系統的數據庫是sqlserver2008,原系統框架是c#,無法二開,因為原系統的合同生成功能出現bug,沒有供…

DeepCritic: SFT+RL兩階段訓練突破LLM自我監督!顯著提升大模型的自我批判能力!!

摘要:隨著大型語言模型(LLMs)的迅速發展,對其輸出進行準確反饋和可擴展監督成為一個迫切且關鍵的問題。利用LLMs作為批評模型以實現自動化監督是一個有前景的解決方案。在本研究中,我們專注于研究并提升LLMs在數學批評…

【深度學習】深度學習中的張量:從多維數組到智能計算單元

? 一、n維數組(張量,Tensor) 1. 定義 張量(Tensor)是一個通用的n維數組數據結構。 它的維度(維數)決定了它的形狀,例如: 維度名稱舉例說明0維標量(scalar…

以太網MDI信號PCB EMC設計要點

1. PHY側和RJ45連接器側通用MDI布局建議 1. MDI差分對保持對稱走線,走線上的焊盤封裝應一致,焊盤放置位置也應對稱。可以減少EMI測試中的模式轉換。 ??2. MDI走線應保持阻抗匹配,從而減少信號線上的反射。 ??3. MDI走線下需有連續完整的接…

深入淺出WebGL:在瀏覽器中解鎖3D世界的魔法鑰匙

WebGL:在瀏覽器中解鎖3D世界的魔法鑰匙 引言:網頁的邊界正在消失 在數字化浪潮的推動下,網頁早已不再是靜態信息的展示窗口。如今,我們可以在瀏覽器中體驗逼真的3D游戲、交互式數據可視化、虛擬實驗室,甚至沉浸式的V…