偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

如何優(yōu)雅的實(shí)現(xiàn)消息通信?

網(wǎng)絡(luò) 通信技術(shù)
作為一名 Web 開發(fā)者,在日常工作中,經(jīng)常都會(huì)遇到消息通信的場(chǎng)景。比如實(shí)現(xiàn)組件間通信、實(shí)現(xiàn)插件間通信、實(shí)現(xiàn)不同的系統(tǒng)間通信。那么針對(duì)這些場(chǎng)景,我們應(yīng)該怎么實(shí)現(xiàn)消息通信呢?

[[339299]]

本文轉(zhuǎn)載自微信公眾號(hào)「全棧修仙之路」,作者semlinker。轉(zhuǎn)載本文請(qǐng)聯(lián)系全棧修仙之路公眾號(hào)。

一、背景

作為一名 Web 開發(fā)者,在日常工作中,經(jīng)常都會(huì)遇到消息通信的場(chǎng)景。比如實(shí)現(xiàn)組件間通信、實(shí)現(xiàn)插件間通信、實(shí)現(xiàn)不同的系統(tǒng)間通信。那么針對(duì)這些場(chǎng)景,我們應(yīng)該怎么實(shí)現(xiàn)消息通信呢?本文阿寶哥將帶大家一起來學(xué)習(xí)如何優(yōu)雅的實(shí)現(xiàn)消息通信。

時(shí)間就這樣過了半個(gè)月,小秦和小王都陸續(xù)找到了阿寶哥,說 “全棧修仙之路” 博客上的 TS 文章都差不多學(xué)完了,他們有空的時(shí)候都會(huì)到 “全棧修仙之路” 博客上查看是否有新發(fā)的 TS 文章。他們覺得這樣挺麻煩的,看能不能在阿寶哥發(fā)完新的 TS 文章之后,主動(dòng)通知他們。

 

好友提的建議,阿寶哥怎能拒絕呢?所以阿寶哥分別跟他們說:“我會(huì)給博客加個(gè)訂閱的功能,功能發(fā)布后,你填寫一下郵箱地址。以后發(fā)布新的 TS 文章,系統(tǒng)會(huì)及時(shí)給你發(fā)郵件”。此時(shí)新的流程如下圖所示:

 

在阿寶哥的一頓 “操作” 之后,博客的訂閱功能上線了,阿寶哥第一時(shí)間通知了小秦與小王,讓他們填寫各自的郵箱。之后,每當(dāng)阿寶哥發(fā)布新的 TS 文章,他們就會(huì)收到新的郵件通知了。

阿寶哥是個(gè)技術(shù)宅,對(duì)新的技術(shù)也很感興趣。在遇到 Deno 之后,阿寶哥燃起了學(xué)習(xí) Deno 的熱情,同時(shí)也開啟了新的 Deno 專題。在寫了幾篇 Deno 專題文章之后,兩個(gè)讀者小池和小郭分別聯(lián)系到我,說他們看到了阿寶哥的 Deno 文章,想跟阿寶哥一起學(xué)習(xí) Deno。

在了解他們的情況之后,阿寶哥突然想到了之前小秦與小王提的建議。因此,又是一頓 “操作” 之后,阿寶哥為了博客增加了專題訂閱功能。該功能上線之后,阿寶哥及時(shí)聯(lián)系了小池和小郭,邀請(qǐng)他們訂閱 Deno 專題。之后小池和小郭也成為了阿寶哥博客的訂閱者。現(xiàn)在的流程變成這樣:

 

這個(gè)例子看起來很簡(jiǎn)單,但它背后卻與一些設(shè)計(jì)思想和設(shè)計(jì)模式相關(guān)聯(lián)。因此,接下來阿寶哥將分析以上三個(gè)場(chǎng)景與軟件開發(fā)中一些設(shè)計(jì)思想和設(shè)計(jì)模式的關(guān)聯(lián)性。

二、場(chǎng)景與模式

2.1 消息輪詢模式

在第一個(gè)場(chǎng)景中,小秦和小王為了能查看阿寶哥新發(fā)的 TS 文章,他們需要不斷地訪問 “全棧修仙之路” 博客:

 

這個(gè)場(chǎng)景跟軟件開發(fā)過程中的輪詢模式類似。早期,很多網(wǎng)站為了實(shí)現(xiàn)推送技術(shù),所用的技術(shù)都是輪詢。輪詢是指由瀏覽器每隔一段時(shí)間向服務(wù)器發(fā)出 HTTP 請(qǐng)求,然后服務(wù)器返回最新的數(shù)據(jù)給客戶端。常見的輪詢方式分為輪詢與長(zhǎng)輪詢,它們的區(qū)別如下圖所示:

 

這種傳統(tǒng)的模式帶來很明顯的缺點(diǎn),即瀏覽器需要不斷的向服務(wù)器發(fā)出請(qǐng)求,然而 HTTP 請(qǐng)求與響應(yīng)可能會(huì)包含較長(zhǎng)的頭部,其中真正有效的數(shù)據(jù)可能只是很小的一部分,所以這樣會(huì)消耗很多帶寬資源。為了解決上述問題 HTML5 定義了 WebSocket 協(xié)議,能更好的節(jié)省服務(wù)器資源和帶寬,并且能夠更實(shí)時(shí)地進(jìn)行通訊。

WebSocket 是一種網(wǎng)絡(luò)傳輸協(xié)議,可在單個(gè) TCP 連接上進(jìn)行全雙工通信,位于 OSI 模型的應(yīng)用層。WebSocket 協(xié)議在 2011 年由 IETF 標(biāo)準(zhǔn)化為 RFC 6455,后由 RFC 7936 補(bǔ)充規(guī)范。

既然已經(jīng)提到了 OSI(Open System Interconnection Model)模型,這里阿寶哥來分享一張很生動(dòng)、很形象描述 OSI 模型的示意圖:

 

(圖片來源:https://www.networkingsphere.com/2019/07/what-is-osi-model.html)

WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡(jiǎn)單,允許服務(wù)端主動(dòng)向客戶端推送數(shù)據(jù)。在 WebSocket API 中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸。

介紹完輪詢和 WebSocket 的相關(guān)內(nèi)容之后,接下來我們來看一下 XHR Polling 與 WebSocket 之間的區(qū)別:

 

對(duì)于 XHR Polling 與 WebSocket 來說,它們分別對(duì)應(yīng)了消息通信的兩種模式,即 Pull(拉)模式與 Push(推)模式:

 

場(chǎng)景一我們就介紹到這里,對(duì)輪詢和 WebSocket 感興趣的小伙伴可以閱讀阿寶哥寫的“你不知道的 WebSocket” 這一篇文章。下面我們來繼續(xù)分析第二個(gè)場(chǎng)景。

2.2 觀察者模式

在第二個(gè)場(chǎng)景中,為了讓小秦和小王能及時(shí)收到阿寶哥新發(fā)布的 TS 文章,阿寶哥給博客增加了訂閱功能。這里假設(shè)阿寶哥博客一開始只發(fā)布 TS 專題的文章。

 

針對(duì)這個(gè)場(chǎng)景,我們可以考慮使用設(shè)計(jì)模式中觀察者模式來實(shí)現(xiàn)上述功能。觀察者模式,它定義了一種一對(duì)多的關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象,這個(gè)主題對(duì)象的狀態(tài)發(fā)生變化時(shí)就會(huì)通知所有的觀察者對(duì)象,使得它們能夠自動(dòng)更新自己。

在觀察者模式中有兩個(gè)主要角色:Subject(主題)和 Observer(觀察者)。

 

在第二個(gè)場(chǎng)景中,Subject(主題)就是阿寶哥的 TS 專題文章,而觀察者就是小秦和小王。由于觀察者模式支持簡(jiǎn)單的廣播通信,當(dāng)消息更新時(shí),會(huì)自動(dòng)通知所有的觀察者。因此對(duì)于第二個(gè)場(chǎng)景,我們可以考慮使用觀察者設(shè)計(jì)模式來實(shí)現(xiàn)上述的功能。接下來,我們來繼續(xù)分析第三個(gè)場(chǎng)景。

2.3 發(fā)布訂閱模式

在第三個(gè)場(chǎng)景中,為了讓小池和小郭能及時(shí)收到阿寶哥新發(fā)布的 Deno 文章,阿寶哥給博客增加了專題訂閱功能。即支持為阿寶哥博客的訂閱者分別推送新發(fā)布的 TS 或 Deno 文章。

 

針對(duì)這個(gè)場(chǎng)景,我們可以考慮使用發(fā)布訂閱模式來實(shí)現(xiàn)上述功能。在軟件架構(gòu)中,發(fā)布 — 訂閱是一種消息范式,消息的發(fā)送者(稱為發(fā)布者)不會(huì)將消息直接發(fā)送給特定的接收者(稱為訂閱者)。而是將發(fā)布的消息分為不同的類別,然后分別發(fā)送給不同的訂閱者。同樣的,訂閱者可以表達(dá)對(duì)一個(gè)或多個(gè)類別的興趣,只接收感興趣的消息,無需了解哪些發(fā)布者存在。

在發(fā)布訂閱模式中有三個(gè)主要角色:Publisher(發(fā)布者)、 Channels(通道)和 Subscriber(訂閱者)。

 

在第三個(gè)場(chǎng)景中,Publisher(發(fā)布者)是阿寶哥,Channels(通道)中 Topic A 和 Topic B 分別對(duì)應(yīng)于 TS 專題和 Deno 專題,而 Subscriber(訂閱者)就是小秦、小王、小池和小郭。好的,了解完發(fā)布訂閱模式,下面我們來介紹一下它的一些應(yīng)用場(chǎng)景。

三、發(fā)布訂閱模式的應(yīng)用

3.1 前端框架中模塊/頁面間消息通信

在一些主流的前端框架中,內(nèi)部也會(huì)提供用于模塊間或頁面間通信的組件。比如在 Vue 框架中,我們可以通過 new Vue() 來創(chuàng)建 EventBus 組件。而在 Ionic 3 中我們可以使用 ionic-angular 模塊中的 Events 組件來實(shí)現(xiàn)模塊間或頁面間的消息通信。下面我們來分別介紹在 Vue 和 Ionic 中如何實(shí)現(xiàn)模塊/頁面間的消息通信。

3.1.1 Vue 使用 EventBus 進(jìn)行消息通信

在 Vue 中我們可以通過創(chuàng)建 EventBus 來實(shí)現(xiàn)組件間或模塊間的消息通信,使用方式很簡(jiǎn)單。在下圖中包含兩個(gè) Vue 組件:Greet 和 Alert 組件。Alert 組件用于顯示消息,而 Greet 組件中包含一個(gè)按鈕,即下圖中 ”顯示問候消息“ 的按鈕。當(dāng)用戶點(diǎn)擊按鈕時(shí),Greet 組件會(huì)通過 EventBus 把消息傳遞給 Alert 組件,該組件接收到消息后,會(huì)調(diào)用 alert 方法把收到的消息顯示出來。

 

以上示例對(duì)應(yīng)的代碼如下:

main.js

  1. Vue.prototype.$bus = new Vue(); 

Alert.vue

  1. <script> 
  2. export default { 
  3.   name"alert"
  4.   created() { 
  5.     // 監(jiān)聽alert:message事件 
  6.     this.$bus.$on("alert:message", msg => { 
  7.       this.showMessage(msg); 
  8.     }); 
  9.   }, 
  10.   methods: { 
  11.     showMessage(msg) { 
  12.       alert(msg); 
  13.     }, 
  14.   }, 
  15.   beforeDestroy: function() { 
  16.     // 組件銷毀時(shí),移除alert:message事件監(jiān)聽 
  17.     this.$bus.$off("alert:message"); 
  18.   } 
  19. </script> 

 

Greet.vue

  1. <template> 
  2.   <div> 
  3.     <button @click="greet(message)">顯示問候信息</button> 
  4.   </div> 
  5. </template> 
  6.  
  7. <script> 
  8. export default { 
  9.   name"Greet"
  10.   data() { 
  11.     return { 
  12.       message: "大家好,我是阿寶哥"
  13.     }; 
  14.   }, 
  15.   methods: { 
  16.     greet(msg) { 
  17.       this.$bus.$emit("alert:message", msg); 
  18.     } 
  19.   } 
  20. }; 
  21. </script> 

 

3.1.2 Ionic 使用 Events 組件進(jìn)行消息通信

在 Ionic 3 項(xiàng)目中,要實(shí)現(xiàn)頁面間消息通信很簡(jiǎn)單。我們只要通過構(gòu)造注入的方式注入 ionic-angular 模塊中提供的 Events 組件即可。具體的使用示例如下所示:

  1. import { Events } from 'ionic-angular'
  2.  
  3. // first page (publish an event when a user is created) 
  4. constructor(public events: Events) {} 
  5. createUser(user) { 
  6.   console.log('User created!'
  7.   this.events.publish('user:created'userDate.now()); 
  8.  
  9.  
  10. // second page (listen for the user created event after function is called) 
  11. constructor(public events: Events) { 
  12.   events.subscribe('user:created', (usertime) => { 
  13.     // user and time are the same arguments passed in `events.publish(usertime)` 
  14.     console.log('Welcome'user'at'time); 
  15.   }); 

介紹完發(fā)布訂閱模式在 Vue 和 Ionic 框架中的應(yīng)用之后,接下來阿寶哥將介紹該模式在微內(nèi)核架構(gòu)中是如何實(shí)現(xiàn)插件通信的。

3.2 微內(nèi)核架構(gòu)中插件通信

微內(nèi)核架構(gòu)(Microkernel Architecture),有時(shí)也被稱為插件化架構(gòu)(Plug-in Architecture),是一種面向功能進(jìn)行拆分的可擴(kuò)展性架構(gòu),通常用于實(shí)現(xiàn)基于產(chǎn)品的應(yīng)用。微內(nèi)核架構(gòu)模式允許你將其他應(yīng)用程序功能作為插件添加到核心應(yīng)用程序,從而提供可擴(kuò)展性以及功能分離和隔離。

微內(nèi)核架構(gòu)模式包括兩種類型的架構(gòu)組件:核心系統(tǒng)(Core System)和插件模塊(Plug-in modules)。應(yīng)用邏輯被分割為獨(dú)立的插件模塊和核心系統(tǒng),提供了可擴(kuò)展性、靈活性、功能隔離和自定義處理邏輯的特性。

 

對(duì)于微內(nèi)核的核心系統(tǒng)設(shè)計(jì)來說,它涉及三個(gè)關(guān)鍵技術(shù):插件管理、插件連接和插件通信,這里我們重點(diǎn)來分析一下插件通信。

插件通信是指插件間的通信。雖然設(shè)計(jì)的時(shí)候插件間是完全解耦的,但實(shí)際業(yè)務(wù)運(yùn)行過程中,必然會(huì)出現(xiàn)某個(gè)業(yè)務(wù)流程需要多個(gè)插件協(xié)作,這就要求兩個(gè)插件間進(jìn)行通信;由于插件之間沒有直接聯(lián)系,通信必須通過核心系統(tǒng),因此核心系統(tǒng)需要提供插件通信機(jī)制。

這種情況和計(jì)算機(jī)類似,計(jì)算機(jī)的 CPU、硬盤、內(nèi)存、網(wǎng)卡是獨(dú)立設(shè)計(jì)的配置,但計(jì)算機(jī)運(yùn)行過程中,CPU 和內(nèi)存、內(nèi)存和硬盤肯定是有通信的,計(jì)算機(jī)通過主板上的總線提供了這些組件之間的通信功能。

 

下面阿寶哥將以基于微內(nèi)核架構(gòu)設(shè)計(jì)的西瓜播放器為例,介紹它的內(nèi)部是如何提供插件通信機(jī)制。在西瓜播放器內(nèi)部,定義了一個(gè) Player 類來創(chuàng)建播放器實(shí)例:

  1. let player = new Player({ 
  2.   id: 'mse'
  3.   url: '//abc.com/**/*.mp4' 
  4. }); 

Player 類繼承于 Proxy 類,而在 Proxy 類內(nèi)部會(huì)通過構(gòu)造繼承的方式繼承 EventEmitter 事件派發(fā)器:

  1. import EventEmitter from 'event-emitter' 
  2.  
  3. class Proxy { 
  4.   constructor (options) { 
  5.     this._hasStart = false
  6.     // 省略大部分代碼 
  7.     EventEmitter(this); 
  8.   } 

所以我們創(chuàng)建的西瓜播放器也是一個(gè)事件派發(fā)器,利用它就可以實(shí)現(xiàn)插件的通信。為了讓大家能夠更好地理解具體的通信流程,我們以內(nèi)置的 poster 插件為例,來看一下它內(nèi)部如何使用事件派發(fā)器。

poster 插件用于在播放器播放音視頻前顯示海報(bào)圖,該插件的使用方式如下:

  1. new Player({ 
  2.   el:document.querySelector('#mse'), 
  3.   url: 'video_url'
  4.   poster: '//abc.com/**/*.png' // 默認(rèn)值"" 
  5. }); 

poster 插件的對(duì)應(yīng)源碼如下:

  1. import Player from '../player' 
  2.  
  3. let poster = function () { 
  4.   let player = this;  
  5.   let util = Player.util 
  6.   let poster = util.createDom('xg-poster''', {}, 'xgplayer-poster'); 
  7.   let root = player.root 
  8.   if (player.config.poster) { 
  9.     poster.style.backgroundImage = `url(${player.config.poster})` 
  10.     root.appendChild(poster) 
  11.   } 
  12.  
  13.   // 監(jiān)聽播放事件,播放時(shí)隱藏封面圖 
  14.   function playFunc () { 
  15.     poster.style.display = 'none' 
  16.   } 
  17.   player.on('play', playFunc) 
  18.  
  19.   // 監(jiān)聽銷毀事件,執(zhí)行清理操作 
  20.   function destroyFunc () { 
  21.     player.off('play', playFunc) 
  22.     player.off('destroy', destroyFunc) 
  23.   } 
  24.   player.once('destroy', destroyFunc) 
  25.  
  26. Player.install('poster', poster) 

(https://github.com/bytedance/xgplayer/blob/master/packages/xgplayer/src/control/poster.js)

通過觀察源碼可知,在注冊(cè) poster 插件時(shí),會(huì)把播放器實(shí)例注入到插件中。之后,在插件內(nèi)部會(huì)使用 player 這個(gè)事件派發(fā)器來監(jiān)聽播放器的 play 和 destroy 事件。當(dāng) poster 插件監(jiān)聽到播放器的 play 事件之后,就會(huì)隱藏海報(bào)圖。而當(dāng) poster 插件監(jiān)聽到播放器的 destroy 事件時(shí),就會(huì)執(zhí)行清理操作,比如移除已綁定的事件。

看到這里我們就已經(jīng)很清楚了,西瓜播放器內(nèi)部使用 EventEmitter 來提供插件通信機(jī)制,每個(gè)插件都會(huì)注入 player 這個(gè)全局的事件派發(fā)器,通過它就可以輕松地實(shí)現(xiàn)插件間通信了。

 

提到 EventEmitter,相信很多小伙伴對(duì)它并不會(huì)陌生。在 Node.js 中有一個(gè)名為 events 的內(nèi)置模塊,通過它我們可以方便地實(shí)現(xiàn)一個(gè)自定義的事件派發(fā)器,比如:

  1. const EventEmitter = require('events'); 
  2.  
  3. class MyEmitter extends EventEmitter {} 
  4.  
  5. const myEmitter = new MyEmitter(); 
  6.  
  7. myEmitter.on('event', () => { 
  8.   console.log('大家好,我是阿寶哥!'); 
  9. }); 
  10.  
  11. myEmitter.emit('event'); 

3.3 基于 Redis 實(shí)現(xiàn)不同系統(tǒng)間通信

在前面我們介紹了發(fā)布訂閱模式在單個(gè)系統(tǒng)中的應(yīng)用。其實(shí),在日常開發(fā)過程中,我們也會(huì)遇到不同系統(tǒng)間通信的問題。接下來阿寶哥將介紹如何利用 Redis 提供的發(fā)布與訂閱功能實(shí)現(xiàn)系統(tǒng)間的通信,不過在介紹具體應(yīng)用前,我們得先熟悉一下 Redis 提供的發(fā)布與訂閱功能。

3.3.1 Redis 發(fā)布與訂閱功能

Redis 訂閱功能

通過 Redis 的 subscribe 命令,我們可以訂閱感興趣的通道,其語法為:SUBSCRIBE channel [channel …]。

  1. ➜  ~ redis-cli 
  2. 127.0.0.1:6379> subscribe deno ts 
  3. Reading messages... (press Ctrl-C to quit) 
  4. 1) "subscribe" 
  5. 2) "deno" 
  6. 3) (integer) 1 
  7. 1) "subscribe" 
  8. 2) "ts" 
  9. 3) (integer) 2 

在上述命令中,我們通過 subscribe 命令訂閱了 deno 和 ts 兩個(gè)通道。接下來我們新開一個(gè)命令行窗口,來測(cè)試 Redis 的發(fā)布功能。

Redis 發(fā)布功能

通過 Redis 的 publish 命令,我們可以為指定的通道發(fā)布消息,其語法為:PUBLISH channel message。

  1. ➜  ~ redis-cli 
  2. 127.0.0.1:6379> publish ts "pub/sub design mode" 
  3. (integer) 1 

當(dāng)成功發(fā)布消息之后,訂閱該通道的客戶端就會(huì)收到消息,對(duì)應(yīng)的控制臺(tái)就會(huì)輸出如下信息:

  1. 1) "message" 
  2. 2) "ts" 
  3. 3) "pub/sub design mode" 

了解完 Redis 的發(fā)布與訂閱功能,接下來阿寶哥將介紹如何利用 Redis 提供的發(fā)布與訂閱功能實(shí)現(xiàn)不同系統(tǒng)間的通信。

3.3.2 實(shí)現(xiàn)不同系統(tǒng)間的通信

這里我們使用 Node.js 的 Express 框架和 redis 模塊來快速搭建不同的 Web 應(yīng)用,首先創(chuàng)建一個(gè)新的 Web 項(xiàng)目并安裝一下相關(guān)的依賴:

  1. $ npm init --yes 
  2. $ npm install express redis 

接著創(chuàng)建一個(gè)發(fā)布者應(yīng)用:

publisher.js

  1. const redis = require("redis"); 
  2. const express = require("express"); 
  3.  
  4. const publisher = redis.createClient(); 
  5.  
  6. const app = express(); 
  7.  
  8. app.get("/", (req, res) => { 
  9.   const article = { 
  10.     id: "666"
  11.     name"TypeScript實(shí)戰(zhàn)之發(fā)布訂閱模式"
  12.   }; 
  13.  
  14.   publisher.publish("ts", JSON.stringify(article)); 
  15.   res.send("阿寶哥寫了一篇TS文章"); 
  16. }); 
  17.  
  18. app.listen(3005, () => { 
  19.   console.log(`server is listening on PORT 3005`); 
  20. }); 

然后分別創(chuàng)建兩個(gè)訂閱者應(yīng)用:

subscriber-1.js

  1. const redis = require("redis"); 
  2. const express = require("express"); 
  3.  
  4. const subscriber = redis.createClient(); 
  5.  
  6. const app = express(); 
  7.  
  8. subscriber.on("message", (channel, message) => { 
  9.   console.log("小王收到了阿寶哥的TS文章: " + message); 
  10. }); 
  11.  
  12. subscriber.subscribe("ts"); 
  13.  
  14. app.get("/", (req, res) => { 
  15.   res.send("我是阿寶哥的粉絲,小王"); 
  16. }); 
  17.  
  18. app.listen(3006, () => { 
  19.   console.log("server is listening to port 3006"); 
  20. }); 

subscriber-2.js

  1. const redis = require("redis"); 
  2. const express = require("express"); 
  3.  
  4. const subscriber = redis.createClient(); 
  5.  
  6. // https://dev.to/ganeshmani/implementing-redis-pub-sub-in-node-js-application-12he 
  7. const app = express(); 
  8.  
  9. subscriber.on("message", (channel, message) => { 
  10.   console.log("小秦收到了阿寶哥的TS文章: " + message); 
  11. }); 
  12.  
  13. subscriber.subscribe("ts"); 
  14.  
  15. app.get("/", (req, res) => { 
  16.   res.send("我是阿寶哥的粉絲,小秦"); 
  17. }); 
  18.  
  19. app.listen(3007, () => { 
  20.   console.log("server is listening to port 3007"); 
  21. }); 

接著分別啟動(dòng)上面的三個(gè)應(yīng)用,當(dāng)所有應(yīng)用都成功啟動(dòng)之后,在瀏覽器中訪問 http://localhost:3005/ 地址,此時(shí)上面的兩個(gè)訂閱者應(yīng)用對(duì)應(yīng)的終端會(huì)分別輸出以下信息:

subscriber-1.js

  1. server is listening to port 3006 
  2. 小王收到了阿寶哥的TS文章: {"id":"666","name":"TypeScript實(shí)戰(zhàn)之發(fā)布訂閱模式"

subscriber-2.js

  1. server is listening to port 3007 
  2. 小秦收到了阿寶哥的TS文章: {"id":"666","name":"TypeScript實(shí)戰(zhàn)之發(fā)布訂閱模式"

以上示例對(duì)應(yīng)的通信流程如下圖所示:

 

到這里發(fā)布訂閱模式的應(yīng)用場(chǎng)景,已經(jīng)介紹完了。最后,阿寶哥來介紹一下如何使用 TS 實(shí)現(xiàn)一個(gè)支持發(fā)布與訂閱功能的 EventEmitter 組件。

四、發(fā)布訂閱模式實(shí)戰(zhàn)

4.1 定義 EventEmitter 類

  1. type EventHandler = (...args: any[]) => any
  2.  
  3. class EventEmitter { 
  4.   private c = new Map<string, EventHandler[]>(); 
  5.  
  6.   // 訂閱指定的主題 
  7.   subscribe(topic: string, ...handlers: EventHandler[]) { 
  8.     let topics = this.c.get(topic); 
  9.     if (!topics) { 
  10.       this.c.set(topic, topics = []); 
  11.     } 
  12.     topics.push(...handlers); 
  13.   } 
  14.  
  15.   // 取消訂閱指定的主題 
  16.   unsubscribe(topic: string, handler?: EventHandler): boolean { 
  17.     if (!handler) { 
  18.       return this.c.delete(topic); 
  19.     } 
  20.  
  21.     const topics = this.c.get(topic); 
  22.     if (!topics) { 
  23.       return false
  24.     } 
  25.      
  26.     const index = topics.indexOf(handler); 
  27.  
  28.     if (index < 0) { 
  29.       return false
  30.     } 
  31.     topics.splice(index, 1); 
  32.     if (topics.length === 0) { 
  33.       this.c.delete(topic); 
  34.     } 
  35.     return true
  36.   } 
  37.  
  38.   // 為指定的主題發(fā)布消息 
  39.   publish(topic: string, ...args: any[]): any[] | null { 
  40.     const topics = this.c.get(topic); 
  41.     if (!topics) { 
  42.       return null
  43.     } 
  44.     return topics.map(handler => { 
  45.       try { 
  46.         return handler(...args); 
  47.       } catch (e) { 
  48.         console.error(e); 
  49.         return null
  50.       } 
  51.     }); 
  52.   } 

4.2 使用示例

  1. const eventEmitter = new EventEmitter(); 
  2. eventEmitter.subscribe("ts", (msg) => console.log(`收到訂閱的消息:${msg}`) ); 
  3.  
  4. eventEmitter.publish("ts""TypeScript發(fā)布訂閱模式"); 
  5. eventEmitter.unsubscribe("ts"); 
  6. eventEmitter.publish("ts""TypeScript發(fā)布訂閱模式"); 

以上代碼成功運(yùn)行之后,控制臺(tái)會(huì)輸出以下信息:

  1. 收到訂閱的消息:TypeScript發(fā)布訂閱模式 

收到訂閱的消息:TypeScript發(fā)布訂閱模式

五、參考資源

維基百科 - 發(fā)布/訂閱

Ionic 3 - Events

 

implementing-redis-pub-sub-in-node-js-application

 

責(zé)任編輯:武曉燕 來源: 全棧修仙之路
相關(guān)推薦

2020-03-27 15:10:23

SpringJava框架

2022-02-18 17:34:47

數(shù)組多維五維數(shù)組

2020-08-24 13:35:59

trycatchJava

2024-01-17 10:16:22

前端國際化消息鍵

2023-01-31 10:29:26

JavaScript國際化國際化庫

2013-07-11 15:14:31

華為統(tǒng)一通信統(tǒng)一通信華為

2024-12-18 12:10:00

2023-10-27 08:20:12

springboot微服務(wù)

2022-11-15 07:50:47

ORM鏈?zhǔn)讲僮?/a>刪除

2022-11-11 07:48:56

ORM鏈?zhǔn)?/a>輪播圖

2021-05-12 22:07:43

并發(fā)編排任務(wù)

2025-06-04 01:00:00

2021-05-09 19:41:35

JavaScript 前端同源通信

2021-01-22 10:58:16

網(wǎng)絡(luò)安全進(jìn)程間碼如

2024-05-16 08:10:17

RabbitMQ軟件通信機(jī)制

2022-08-02 11:27:25

RabbitMQ消息路由

2021-03-09 13:18:53

加密解密參數(shù)

2022-06-04 12:25:10

解密加密過濾器

2015-11-26 10:53:45

LinuxWindowsMac OS

2021-01-19 10:35:49

JVM場(chǎng)景函數(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)