1. 程式人生 > >JavaScript之釋出-訂閱模式

JavaScript之釋出-訂閱模式

現實生活中的釋出-訂閱模式

不論是在程式世界裡還是現實生活中,釋出—訂閱模式的應用都非常廣泛。我們先看一下現實中的例子。
小明最近看上了一套房子,到了售樓處之後才被告知,該樓盤的房子早已售罄。好在售樓MM告訴小明,不久後還有一些尾盤推出。開發商正在辦理相關手續,手續辦好後便可以購買。但到底是什麼時候,目前還沒有人能夠知道。
於是小明記下了售樓處的電話,以後每天都會打電話過去詢問是不是已經到了購買時間。除了小明,還有小紅,小強,小龍也會每天向售樓處諮詢這個問題。一個星期過後,售樓MM決定辭職,因為厭倦了每天回答1000個相同的電話。
當然現實中沒有這麼笨的銷售公司,實際上故事是這樣的:小明離開之前,把電話號碼留在售樓處。售樓MM答應他,新樓盤一推出就馬上發信息通知小明。小紅、小強、小龍也是一樣,他們的電話號碼都被記在售樓處的花名冊上,新樓盤推出的時候,售樓MM會翻開花名冊,遍歷上面的電話號碼,依次傳送一條簡訊通知他們。

DOM事件

實際上我們之前就一直在使用釋出訂閱模式,當我們繫結一個DOM事件的時候,其實就是在使用這個模式,思考下面程式碼:

document.body.addEventListener(‘click’,function(){  
  alert(2);  
},false);  
document.body.click();

這裡需要監控使用者點選document.body的動作,但是我們沒辦法預知使用者將在什麼時候點選。所以我們訂閱document.body上的click事件,當body節點被點選時,body節點便會向訂閱者釋出這個訊息。

釋出訂閱模式的優點

  1. 可以廣泛應用於非同步程式設計,它可以代替我們傳統的回撥函式,我們不需要關注物件在非同步執行階段的內部狀態,我們只關心事件完成的時間點。

  2. 取代物件之間硬編碼通知機制,一個物件不必顯式呼叫另一個物件的介面,而是鬆耦合的聯絡在一起
    雖然不知道彼此的細節,但不影響相互通訊。更重要的是,其中一個物件改變不會影響另一個物件。

模式的通用實現

var Event = (function(){
    var list = {},
        listen,
        trigger,
        remove;
    listen = function(key,fn){ //監聽事件函式
        if(!list[key]){
            list[key] = []; //如果事件列表中還沒有key值名稱空間,建立
} list[key].push(fn); //將回調函式推入物件的“鍵”對應的“值”回撥陣列 }; trigger = function(){ //觸發事件函式 var key = Array.prototype.shift.call(arguments); //第一個引數指定“鍵” msg = list[key]; if(!msg || msg.length === 0){ return false; //如果回撥陣列不存在或為空則返回false } for(var i = 0; i < msg.length; i++){ msg[i].apply(this, arguments); //迴圈回撥陣列執行回撥函式 } }; remove = function(key, fn){ //移除事件函式 var msg = list[key]; if(!msg){ return false; //事件不存在直接返回false } if(!fn){ delete list[key]; //如果沒有後續引數,則刪除整個回撥陣列 }else{ for(var i = 0; i < msg.length; i++){ if(fn === msg[i]){ msg.splice(i, 1); //刪除特定回撥陣列中的回撥函式 } } } }; return { listen: listen, trigger: trigger, remove: remove } })(); var fn = function(data){ console.log(data + '的推送訊息:xxxxxx......'); } Event.listen('a', fn); Event.trigger('a', '2016.11.26'); Event.remove('a', fn);