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

下載本文檔

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

文檔簡介

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

我們先來實現(xià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ā)布者的每個消息,但是呢,對于小紅來說,她只想接收顏色為紅色的消息,不想接收顏色為黑色的消息,為此我們需要對代碼進(jìn)行如下改造下,我們可以先增加一個key,使訂閱者只訂閱自己感興趣的消息。

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

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

//增加訂閱者

shoeObj.listen=function(key,fn){

if(!this.list[key]){

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

this.list[key]=[];

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

//發(fā)布消息

shoeObj.trigger=function(){

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

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

//如果沒有訂閱過該消息的話,則返回

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

return;

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

fn.apply(this,arguments);//arguments是發(fā)布消息時附送的參數(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);

上面的代碼,我們再來運(yùn)行打印下如下:

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

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

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

//如果沒有訂閱過該消息的話,則返回

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

return;

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

fn.apply(this,arguments);

};

我們在定義一個initEvent函數(shù),這個函數(shù)使所有的普通對象都具有發(fā)布訂閱功能,如下代碼:

varinitEvent=function(obj){

for(variinevent){

obj[i]=event[i];

};

//我們再來測試下,我們還是給shoeObj這個對象添加發(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);

如何取消訂閱事件?

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

如下代碼:

event.remove=function(key,fn){

varfns=this.list[key];

//如果key對應(yīng)的消息沒有訂閱過的話,則返回

if(!fns){

returnfalse;

//如果沒有傳入具體的回調(diào)函數(shù),表示需要取消key對應(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ù)

};

測試代碼如下:

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ā)布訂閱對象代碼封裝

我們再來看看我們傳統(tǒng)的ajax請求吧,比如我們傳統(tǒng)的ajax請求,請求成功后需要做如下事情:

渲染數(shù)據(jù)。使用數(shù)據(jù)來做一個動畫。

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

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

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

doAnimate(data);//實現(xiàn)動畫

});

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

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

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

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

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

renderData(data);

//訂閱動畫這個消息

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

doAnimate(data);

});

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

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

})();

//測試代碼如下:

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

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

Event.trigger("color",42);

理解模塊間通信

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

buttonid="count"點將我/button

divid="showcount"/div

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

vara=(function(){

varcount=0;

varbutton=document.getElementById("count");

button.onclick=function(){

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

})();

b.j

溫馨提示

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

評論

0/150

提交評論