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