var mailCounter = 0;
// 初始化訂閱,名稱是inbox/newMessage // 呈現消息預覽
var subscriber1 = subscribe("inbox/newMessage", function (topic, data) { // debug模式記錄topic
console.log("A new message was received: ", topic);
// 使用從目標subject傳遞過來的data,一般呈現消息預覽
$(".messageSender").html(data.sender);
$(".messagePreview").html(data.body);
});
// 另外一個訂閱,使用同樣的data數據用於不同的任務
// 通過發布者更新所接收消息的數量
var subscriber2 = subscribe("inbox/newMessage", function (topic, data) {
});
publish("inbox/newMessage", [{
body: "Hey there! How are you doing today?" }]);
// 之後可以通過unsubscribe來取消訂閱
// unsubscribe( subscriber1, );
// unsubscribe( subscriber2 );
$('.newMessageCounter').html(mailCounter++);
sender: "[email protected]",
這裏的中心思想是促進鬆散耦合。通過訂閱另一個對象的特定任務或活動,當任務/活動發生時獲得通知,而不是單個對象直接調用其他對象的方法。
9.5.2 優點
Observer模式和Publish/Subscribe模式鼓勵我們努力思考應用程序不同部分之間的關係。它們也幫助我們識別包含直接關係的層,並且可以用目標集和觀察者進行替換。實際上可以用於將應用程序分解為更小、更鬆散耦合的塊,以改進代碼管理和潛在的複用。使用Observer模式背後的另一個動機是我們需要在哪裏維護相關對象之間的一致性,而無需使類緊密耦合。例如,當一個對象需要能夠通知其他對象,而無需在這些對象方麵做假設時。
在使用任何一種模式時,動態關係可以在觀察者和目標之間存在。這提供了很大的靈活性,當應用程序的不同部分緊密耦合時,這可不是很容易實現的。
雖然它可能不一直是所有問題的最佳解決方案,但這些模式仍是用於設計解耦性係統的最佳工具之一,應該視為所有JavaScript開發人員工具中的一個重要工具。
9.5.3 缺點
因此,這些模式的某些問題實際上源於它的主要好處。在Publish/Subscribe中,通過從訂閱者中解耦發布者,它有時會很難保證應用程序的特定部分按照我們期望的運行。例如,發布者可能會假設:一個或多個訂閱者在監聽它們。倘若我們假設訂閱者需要記錄或輸出一些與應用程序處理有關的錯誤。如果訂閱者執行日誌崩潰了(或出於某種原因無法正常運行),由於係統的解耦特性,發布者就不會看到這一點。
這種模式的另一個缺點是:訂閱者非常無視彼此的存在,並對變換發布者產生的成本視而不見。由於訂閱者和發布者之間的動態關係,很難跟蹤依賴更新。
9.5.4 Publish/Subscribe實現
Publish/Subscribe非常適用於JavaScript生態係統,這主要是因為在其核心,ECMAScript實現是由事件驅動的。在瀏覽器環境下尤其如此,因為DOM將事件是作為腳本編程的主要交互API。
也就是說,在實現代碼裏,無論是ECMAScript還是DOM都不會提供核心對象或方法來創建自定義事件係統(或許除了DOM3 CustomEvent以外,它被綁定到DOM,因此一般是無用的)。
幸運的是,流行的JavaScript庫,比如Dojo、jQuery(自定義事件)和 YUI都擁有一些實用程序可以很容易實現Publish/Subscribe係統。如下是一些有關示例:
// Publish
// jQuery: $(obj).trigger("channel", [arg1, arg2, arg3]);
$( el ).trigger( "/login", [{username:"test", userData:"test"}] ); // Dojo: dojo.publish("channel", [arg1, arg2, arg3] );
dojo.publish( "/login", [{username:"test", userData:"test"}] ); // YUI: el.publish("channel", [arg1, arg2, arg3]);
el.publish( "/login", {username:"test", userData:"test"} ); // Subscribe
// jQuery: $(obj).on( "channel", [data], fn ); $( el ).on( "/login", function( event ){...} ); // Dojo: dojo.subscribe( "channel", fn);
var handle = dojo.subscribe( "/login", function(data){..} ); // YUI: el.on("channel", handler);
el.on( "/login", function( data ){...} ); // Unsubscribe
// jQuery: $(obj).off( "channel" ); $( el ).off( "/login" );
// Dojo: dojo.unsubscribe( handle ); dojo.unsubscribe( handle ); // YUI: el.detach("channel"); el.detach( "/login" );
對於那些希望使用采用純 JavaScript(或其他庫)的Publish/Subscribe模式的人來說,AmplifyJS(http://amplifyjs.com/)包含了一個整潔、與庫無關的實現,它可用於任何庫或工具包。值得一看的類似語言有Radio.js (http://radio.uxder.com/)、PubSubJS (https://github.com/mroderick/PubSubJS)、或Peter Higgins所寫的Pure JS PubSub(https://github.com/phiggins42/bloody-jquery-plugins/blob/)。