javascript
JavaScript中发布/订阅模式的理解
訂閱發布模式的介紹
發布訂閱模式,它定義了一種一對多的關系,可以使多個觀察者對象對一個主題對象進行監聽,當這個主題對象發生改變時,依賴的所有對象都會被通知到。
在生活中我們常常遇到這樣一種情況,我們在使用新聞APP看新聞的時候,每個人喜歡的新聞類型各不一樣,比如我喜歡NBA,但是我們總不可能一天24小時在手機上一遍又一遍的刷新,我們就會去新聞頻道中選擇NBA專欄來收藏,當勇士或者湖人有最新消息,就會通知我們去觀看。
當然從上面的場景中是一個典型的發布訂閱模式,APP的NBA專欄屬于發布者,像我一樣廣大愛好籃球的小伙伴夢就屬于訂閱者,當一有最新的消息,它們就會發布給我們。
實際用途
1.在jquery中很多地方都有發布訂閱的蹤跡,例如事件中on和trigger中封裝的方法。
2.尤大大的Vue,中子父組件通信使用的emit()和on()方法,使得組件得到解耦,開發更加高效。
如何實現訂閱發布模式
1、首先想好誰是發布者(比如上邊的APP的NBA專欄就是發布者);
2、然后給發布者添加一個緩存列表,用于存放回調函數來通知訂閱者(比如上面的我們球迷愛好者收藏了NBA專欄,相當于向發布者注入了通知我們的函數);
3、最后就是發布消息,發布者遍歷這個緩存列表,依次觸發訂閱的函數。
表捉急,端起小板凳,先看一下這個簡單的發布訂閱模式:
let NBAcol={};//自定義一個NBA專欄對象 NBAcol.list=[];// 這里放一個列表用來緩存訂閱者的回調函數 NBAcol.on=function(fun){this.list.push(fun); //把fn先存到列表中 }; //發布事件 NBAcol.emit=function(){this.list.forEach(cb => {cb.apply(this, arguments);});// 當發布的時候再把列表里存的函數依次執行 }; //小明的訂閱NBA專欄 NBAcol.on(function(team){console.log("我訂閱的球隊是:"+team) }) //小李的訂閱NBA專欄 NBAcol.on(function(team){console.log("我訂閱的球隊是:"+team) }) NBAcol.emit('湖人'); NBAcol.emit('勇士'); /* 我訂閱的球隊是:湖人; 我訂閱的球隊是:湖人; 我訂閱的球隊是:勇士; 我訂閱的球隊是:勇士; */ 復制代碼上面就實現了一個簡單的訂閱發布模式,不過從打印結果來看,有些尷尬,因為其實,小明只想訂閱湖人,小李要訂閱勇士。可是專欄都給他們推送了,顯然不太合理。之所以出現這種情況是因為在執行on方法的時候將訂閱函數列表中的函數依次都執行了。所以我們要對代碼進行改造,我們可以先增加一個key,使訂閱者只訂閱自己感興趣的消息。
let NBAcol={};//自定義一個NBA專欄對象 NBAcol.list={};// 這里放一個列表用來緩存訂閱者的回調函數 NBAcol.on=function(key,fun){// 如果還沒有訂閱過此類消息,給該類消息創建一個緩存列表if(!this.list[key]){this.list[key]=[];}this.list[key].push(fun); //把fn先存到列表中 }; //發布事件 NBAcol.emit=function(){let key=Array.prototype.shift.call(arguments);// 取出消息類型名稱let funs=this.list[key];//匹配對應的回調函數的結合if(!funs||funs.length===0){//如果沒有訂閱過消息,則return;return;};funs.forEach(fun => {fun.apply(this, arguments);});// 當發布的時候再把列表里存的函數依次執行 }; //小明的訂閱NBA專欄 NBAcol.on('xiaomin',function(team){console.log("我訂閱的球隊是:"+team) }) //小李的訂閱NBA專欄 NBAcol.on('xiaoli',function(team){console.log("我訂閱的球隊是:"+team) }) NBAcol.emit('xiaomin','湖人'); NBAcol.emit('xiaoli','勇士'); /* 我訂閱的球隊是:湖人; 我訂閱的球隊是:勇士; */ 復制代碼這樣子就可以啦,這個訂閱發布的核心功能已經體現了。
如何取消事件的訂閱
比如上面的列子,假如我們訂閱了很多東西,不喜歡的時候我們要取消訂閱,該怎么辦呢?看如下代碼:
NBAcol.remove=function(key, fun) {// 這回我們加入了取消訂閱的方法let funs = this.list[key];// 如果緩存列表中沒有函數,返回falseif (!funs) return false;// 如果沒有傳對應函數的話// 就會將key值對應緩存列表中的函數都清空掉if (!fun) {funs && (funs.length = 0);} else {// 遍歷緩存列表,看看傳入的fun與哪個函數相同// 如果相同就直接從緩存列表中刪掉即可funs.forEach((cb, i) => {if (cb === fun) {funs.splice(i, 1);}});}}// 取消dog方法的訂閱NBAcol.remove('xiaoli',function(team){console.log("我訂閱的球隊是:"+team)}); 復制代碼這樣就可以取消訂閱啦,但是實際的開源代碼中,封裝遠比這要復雜,比如要考慮訂閱數量,還有多模塊訂閱的封裝等等,所以在這里我們還得在實際的業務模塊中詳細考慮。
發布訂閱模式的缺點:
當然一個任何一個東西都是有兩面性的,同樣發布訂閱模式存在以下問題:
1、創建訂閱者需要消耗一定的時間和內存。
2、雖然可以弱化對象之間的聯系,如果過度使用的話,反而使代碼不好理解及代碼不好維護等等。
轉載于:https://juejin.im/post/5b2e65fee51d4558df370532
總結
以上是生活随笔為你收集整理的JavaScript中发布/订阅模式的理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php实现 简单密码(代码颜色变化)
- 下一篇: 天了噜,Java 8 要停止维护了!