Javascript發(fā)布訂閱模式介紹_第1頁(yè)
Javascript發(fā)布訂閱模式介紹_第2頁(yè)
Javascript發(fā)布訂閱模式介紹_第3頁(yè)
Javascript發(fā)布訂閱模式介紹_第4頁(yè)
Javascript發(fā)布訂閱模式介紹_第5頁(yè)
已閱讀5頁(yè),還剩6頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第Javascript發(fā)布訂閱模式介紹發(fā)布訂閱模式介紹

發(fā)布---訂閱模式又叫觀察者模式,它定義了對(duì)象間的一種一對(duì)多的關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象,當(dāng)一個(gè)對(duì)象發(fā)生改變時(shí),所有依賴于它的對(duì)象都將得到通知。

現(xiàn)實(shí)生活中的發(fā)布-訂閱模式;

比如小紅最近在淘寶網(wǎng)上看上一雙鞋子,但是呢聯(lián)系到賣家后,才發(fā)現(xiàn)這雙鞋賣光了,但是小紅對(duì)這雙鞋又非常喜歡,所以呢聯(lián)系賣家,問(wèn)賣家什么時(shí)候有貨,賣家告訴她,要等一個(gè)星期后才有貨,賣家告訴小紅,要是你喜歡的話,你可以收藏我們的店鋪,等有貨的時(shí)候再通知你,所以小紅收藏了此店鋪,但與此同時(shí),小明,小花等也喜歡這雙鞋,也收藏了該店鋪;等來(lái)貨的時(shí)候就依次會(huì)通知他們;

在上面的故事中,可以看出是一個(gè)典型的發(fā)布訂閱模式,賣家是屬于發(fā)布者,小紅,小明等屬于訂閱者,訂閱該店鋪,賣家作為發(fā)布者,當(dāng)鞋子到了的時(shí)候,會(huì)依次通知小明,小紅等,依次使用旺旺等工具給他們發(fā)布消息;

發(fā)布訂閱模式的優(yōu)點(diǎn):

1.支持簡(jiǎn)單的廣播通信,當(dāng)對(duì)象狀態(tài)發(fā)生改變時(shí),會(huì)自動(dòng)通知已經(jīng)訂閱過(guò)的對(duì)象。

比如上面的列子,小明,小紅不需要天天逛淘寶網(wǎng)看鞋子到了沒(méi)有,在合適的時(shí)間點(diǎn),發(fā)布者(賣家)來(lái)貨了的時(shí)候,會(huì)通知該訂閱者(小紅,小明等人)。

2.發(fā)布者與訂閱者耦合性降低,發(fā)布者只管發(fā)布一條消息出去,它不關(guān)心這條消息如何被訂閱者使用,同時(shí),訂閱者只監(jiān)聽(tīng)發(fā)布者的事件名,只要發(fā)布者的事件名不變,它不管發(fā)布者如何改變;同理賣家(發(fā)布者)它只需要將鞋子來(lái)貨的這件事告訴訂閱者(買家),他不管買家到底買還是不買,還是買其他賣家的。只要鞋子到貨了就通知訂閱者即可。

對(duì)于第一點(diǎn),我們?nèi)粘9ぷ髦幸步?jīng)常使用到,比如我們的ajax請(qǐng)求,請(qǐng)求有成功(success)和失敗(error)的回調(diào)函數(shù),我們可以訂閱ajax的success和error事件。我們并不關(guān)心對(duì)象在異步運(yùn)行的狀態(tài),我們只關(guān)心success的時(shí)候或者error的時(shí)候我們要做點(diǎn)我們自己的事情就可以了~

發(fā)布訂閱模式的缺點(diǎn):

創(chuàng)建訂閱者需要消耗一定的時(shí)間和內(nèi)存。雖然可以弱化對(duì)象之間的聯(lián)系,如果過(guò)度使用的話,反而使代碼不好理解及代碼不好維護(hù)等等。

如何實(shí)現(xiàn)發(fā)布--訂閱模式?

首先要想好誰(shuí)是發(fā)布者(比如上面的賣家)。然后給發(fā)布者添加一個(gè)緩存列表,用于存放回調(diào)函數(shù)來(lái)通知訂閱者(比如上面的買家收藏了賣家的店鋪,賣家通過(guò)收藏了該店鋪的一個(gè)列表名單)。最后就是發(fā)布消息,發(fā)布者遍歷這個(gè)緩存列表,依次觸發(fā)里面存放的訂閱者回調(diào)函數(shù)。

我們還可以在回調(diào)函數(shù)里面添加一點(diǎn)參數(shù),比如鞋子的顏色,鞋子尺碼等信息;

我們先來(lái)實(shí)現(xiàn)下簡(jiǎn)單的發(fā)布-訂閱模式;代碼如下:

varshoeObj={};//定義發(fā)布者

shoeObj.list=[];//緩存列表存放訂閱者回調(diào)函數(shù)

//增加訂閱者

shoeObj.listen=function(fn){

shoeObj.list.push(fn);//訂閱消息添加到緩存列表

//發(fā)布消息

shoeObj.trigger=function(){

for(vari=0,fn;fn=this.list[i++];){

fn.apply(this,arguments);

//小紅訂閱如下消息

shoeObj.listen(function(color,size){

console.log("顏色是:"+color);

console.log("尺碼是:"+size);

//小花訂閱如下消息

shoeObj.listen(function(color,size){

console.log("再次打印顏色是:"+color);

console.log("再次打印尺碼是:"+size);

shoeObj.trigger("紅色",40);

shoeObj.trigger("黑色",42);

運(yùn)行結(jié)果如下:

打印如上截圖,我們看到訂閱者接收到發(fā)布者的每個(gè)消息,但是呢,對(duì)于小紅來(lái)說(shuō),她只想接收顏色為紅色的消息,不想接收顏色為黑色的消息,為此我們需要對(duì)代碼進(jìn)行如下改造下,我們可以先增加一個(gè)key,使訂閱者只訂閱自己感興趣的消息。

varshoeObj={};//定義發(fā)布者

shoeObj.list=[];//緩存列表存放訂閱者回調(diào)函數(shù)

//增加訂閱者

shoeObj.listen=function(key,fn){

if(!this.list[key]){

//如果還沒(méi)有訂閱過(guò)此類消息,給該類消息創(chuàng)建一個(gè)緩存列表

this.list[key]=[];

this.list[key].push(fn);//訂閱消息添加到緩存列表

//發(fā)布消息

shoeObj.trigger=function(){

varkey=Atotype.shift.call(arguments);//取出消息類型名稱

varfns=this.list[key];//取出該消息對(duì)應(yīng)的回調(diào)函數(shù)的集合

//如果沒(méi)有訂閱過(guò)該消息的話,則返回

if(!fns||fns.length===0){

return;

for(vari=0,fn;fn=fns[i++];){

fn.apply(this,arguments);//arguments是發(fā)布消息時(shí)附送的參數(shù)

//小紅訂閱如下消息

shoeObj.listen('red',function(size){

console.log("尺碼是:"+size);

//小花訂閱如下消息

shoeObj.listen('block',function(size){

console.log("再次打印尺碼是:"+size);

shoeObj.trigger("red",40);

shoeObj.trigger("block",42);

上面的代碼,我們?cè)賮?lái)運(yùn)行打印下如下:

可以看到,訂閱者只訂閱自己感興趣的消息了;

發(fā)布---訂閱模式的代碼封裝

我們知道,對(duì)于上面的代碼,小紅去買鞋這么一個(gè)對(duì)象shoeObj進(jìn)行訂閱,但是如果以后我們需要對(duì)買房子或者其他的對(duì)象進(jìn)行訂閱呢,我們需要復(fù)制上面的代碼,再重新改下里面的對(duì)象代碼;為此我們需要進(jìn)行代碼封裝;

如下代碼封裝:

varevent={

list:[],

listen:function(key,fn){

if(!this.list[key]){

this.list[key]=[];

//訂閱的消息添加到緩存列表中

this.list[key].push(fn);

trigger:function(){

varkey=Atotype.shift.call(arguments);

varfns=this.list[key];

//如果沒(méi)有訂閱過(guò)該消息的話,則返回

if(!fns||fns.length===0){

return;

for(vari=0,fn;fn=fns[i++];){

fn.apply(this,arguments);

};

我們?cè)诙x一個(gè)initEvent函數(shù),這個(gè)函數(shù)使所有的普通對(duì)象都具有發(fā)布訂閱功能,如下代碼:

varinitEvent=function(obj){

for(variinevent){

obj[i]=event[i];

};

//我們?cè)賮?lái)測(cè)試下,我們還是給shoeObj這個(gè)對(duì)象添加發(fā)布-訂閱功能;

varshoeObj={};

initEvent(shoeObj);

//小紅訂閱如下消息

shoeObj.listen('red',function(size){

console.log("尺碼是:"+size);

//小花訂閱如下消息

shoeObj.listen('block',function(size){

console.log("再次打印尺碼是:"+size);

shoeObj.trigger("red",40);

shoeObj.trigger("block",42);

如何取消訂閱事件?

比如上面的列子,小紅她突然不想買鞋子了,那么對(duì)于賣家的店鋪他不想再接受該店鋪的消息,那么小紅可以取消該店鋪的訂閱。

如下代碼:

event.remove=function(key,fn){

varfns=this.list[key];

//如果key對(duì)應(yīng)的消息沒(méi)有訂閱過(guò)的話,則返回

if(!fns){

returnfalse;

//如果沒(méi)有傳入具體的回調(diào)函數(shù),表示需要取消key對(duì)應(yīng)消息的所有訂閱

if(!fn){

fn(fns.length=0);

}else{

for(vari=fns.length-1;ii--){

var_fn=fns[i];

if(_fn===fn){

fns.splice(i,1);//刪除訂閱者的回調(diào)函數(shù)

};

測(cè)試代碼如下:

varinitEvent=function(obj){

for(variinevent){

obj[i]=event[i];

varshoeObj={};

initEvent(shoeObj);

//小紅訂閱如下消息

shoeObj.listen('red',fn1=function(size){

console.log("尺碼是:"+size);

//小花訂閱如下消息

shoeObj.listen('red',fn2=function(size){

console.log("再次打印尺碼是:"+size);

shoeObj.remove("red",fn1);

shoeObj.trigger("red",42);

運(yùn)行結(jié)果如下:

全局--發(fā)布訂閱對(duì)象代碼封裝

我們?cè)賮?lái)看看我們傳統(tǒng)的ajax請(qǐng)求吧,比如我們傳統(tǒng)的ajax請(qǐng)求,請(qǐng)求成功后需要做如下事情:

渲染數(shù)據(jù)。使用數(shù)據(jù)來(lái)做一個(gè)動(dòng)畫(huà)。

那么我們以前肯定是如下寫代碼:

$.ajax(“/index.php”,function(data){

rendedData(data);//渲染數(shù)據(jù)

doAnimate(data);//實(shí)現(xiàn)動(dòng)畫(huà)

});

假如以后還需要做點(diǎn)事情的話,我們還需要在里面寫調(diào)用的方法;這樣代碼就耦合性很高,那么我們現(xiàn)在使用發(fā)布-訂閱模式來(lái)看如何重構(gòu)上面的業(yè)務(wù)需求代碼;

$.ajax(“/index.php”,function(data){

Obj.trigger(‘success',data);//發(fā)布請(qǐng)求成功后的消息

//下面我們來(lái)訂閱此消息,比如我現(xiàn)在訂閱渲染數(shù)據(jù)這個(gè)消息;

Obj.listen(“success”,function(data){

renderData(data);

//訂閱動(dòng)畫(huà)這個(gè)消息

Obj.listen(“success”,function(data){

doAnimate(data);

});

為此我們可以封裝一個(gè)全局發(fā)布-訂閱模式對(duì)象;如下代碼:

varEvent=(function(){

varlist={},

listen,

trigger,

remove;

listen=function(key,fn){

if(!list[key]){

list[key]=[];

list[key].push(fn);

trigger=function(){

varkey=Atotype.shift.call(arguments),

fns=list[key];

if(!fns||fns.length===0){

returnfalse;

for(vari=0,fn;fn=fns[i++];){

fn.apply(this,arguments);

remove=function(key,fn){

varfns=list[key];

if(!fns){

returnfalse;

if(!fn){

fns(fns.length=0);

}else{

for(vari=fns.length-1;ii--){

var_fn=fns[i];

if(_fn===fn){

fns.splice(i,1);

return{

listen:listen,

trigger:trigger,

remove:remove

})();

//測(cè)試代碼如下:

Event.listen("color",function(size){

console.log("尺碼為:"+size);//打印出尺碼為42

Event.trigger("color",42);

理解模塊間通信

我們使用上面封裝的全局的發(fā)布-訂閱對(duì)象來(lái)實(shí)現(xiàn)兩個(gè)模塊之間的通信問(wèn)題;比如現(xiàn)在有一個(gè)頁(yè)面有一個(gè)按鈕,每次點(diǎn)擊此按鈕后,div中會(huì)顯示此按鈕被點(diǎn)擊的總次數(shù);如下代碼:

buttonid="count"點(diǎn)將我/button

divid="showcount"/div

我們中的a.js負(fù)責(zé)處理點(diǎn)擊操作及發(fā)布消息;如下JS代碼:

vara=(function(){

varcount=0;

varbutton=document.getElementById("count");

button.onclick=function(){

Event.trigger("add",count++);

})();

b.j

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論