




版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 市場開發(fā)合作協(xié)議及附件
- 專業(yè)技能培訓(xùn)合格證明書(8篇)
- 農(nóng)業(yè)養(yǎng)殖技術(shù)改良與應(yīng)用協(xié)議
- 行政管理市場營銷試題及答案總結(jié)
- 企業(yè)戰(zhàn)略與資源配置的動態(tài)關(guān)系試題及答案
- 2025年農(nóng)村住宅建設(shè)規(guī)范:自建住宅買賣合同
- 行政管理本科課程試題及答案總結(jié)
- 行政管理學(xué)考試常見題型試題及答案
- 2025年行政管理考核模式試題及答案
- 建筑工程考試前沿試題及答案分析
- 私人店鋪用工合同協(xié)議
- 豬保價合同協(xié)議
- 玉石代理銷售合同協(xié)議
- 山東2025年山東省公共衛(wèi)生臨床中心招聘博士人才60筆試歷年參考題庫附帶答案詳解
- 2024年臺州市委統(tǒng)戰(zhàn)部下屬事業(yè)單位選聘筆試真題
- 山西太原事業(yè)單位考試《行測》模擬題帶答案2024年
- 政協(xié)理論知識講座課件
- 2025年中考英語第一次模擬考試(蘇州卷)(原卷版)
- 福州一號線盾構(gòu)法地鐵工程整體施工組織設(shè)計
- 購買學(xué)位合同協(xié)議
- 公務(wù)員考試-經(jīng)濟(jì)基礎(chǔ)知識模擬題-計量經(jīng)濟(jì)學(xué)-協(xié)整與誤差修正模型
評論
0/150
提交評論