1. 程式人生 > >釋出 訂閱 訊息系統

釋出 訂閱 訊息系統

1.從監聽與釋出說起

我們寫js程式碼的時候都知道有這樣的事件:我們註冊一個click方法 ,此時我們就為這個按鈕添加了“監聽”,基於“點選”事件的監聽。以此來實現點選按鈕提交表單資料的目的,在這裡,我們通過點(發)擊(布)這個動作,讓系統知道:哦,我要提交這些表單。   這裡的click方法,就是我們所要說的 “釋出”。

2.釋出訊息之後發生了什麼

當我釋出登入訊息的時候,就有很多模組來響應,比如我登入部落格,頁面的頭部展示我的私人資訊,首頁展示我的部落格內容等。就會有很多模組用各自方法對這個資訊進行處理,那麼這些方法存放在哪裡呢?我可以建立一個物件
<script type="text/javascript">
    var callback = {};
</script>
這些方法有很多,而每個方法又對應很多回調函式,我需要對這些方法資料進行梳理:
<script type="text/javascript">
	var callback = {
		login: [
			function(){},//head回撥
			function(){}//內容回撥
		],
		req: [
			function(){},
			function(){}
		]
		...
	}
</script>
比如:我發出 login 訊息,就要找到login對應的回撥方法,去處理login產生的結果,將結果儲存在callback裡。

3.一般的訊息處理方法

比如有一個登入框,我登入成功後頁面頂部改變,內容區域顯示我的個人資訊,一般我們可以這樣寫:
<script type="text/javascript">
	
	(function() {
			$.ajax({
				url:'http://blog.csdn.net/lihchweb',
				data:{},
				success: function() {
				//成功了
				$("#head name").html("lihouchun");
				$("#content").html(infos);
				//....
				//....
				}
			})
		})();
</script>


這種簡單粗暴,哪個地方需要響應,他就去修改哪個地方,處理問題的方法很集中,耦合性比較高。試想一下如果有很多需要響應的部分呢? 這顯然不是我們想要的,一方面他並沒有模組化,程式碼邏輯容易混亂,也造成了內部的變數命名比較混亂。另一方面:因為登入的程式碼邏輯影響著其他部分,它自身又不能很好的維護自身的所有邏輯。
而我們又想要去解決這個問題,那麼釋出,訂閱,訊息系統來了。

4. 改進的方法:降低耦合度,維護自身邏輯

先看寫法:
<script type="text/javascript">
	//我是head的程式碼邏輯
	(function(){
		core.listen('login', function(info) {
			$("#head name").html(info.name);
		});
	})()

	//我是content的程式碼邏輯
	(function() {
		core.listen('login', function(info) {
			$("#content").html(info.content);
		})
	})()

	//我是登入的邏輯
	(function() {
		$.ajax({
			url:'http://blog.csdn.net/lihchweb',
			data:{},
			success: function(info) {
				core.send('login', info)	
			}
		})
	})();
</script>

這樣處理問題的方法就回到的各自的邏輯當中。當我登入完成的時候,各個部分單獨處理自己的問題,模組更獨立,程式碼易維護且不易出錯。 這就是訊息機制。 這個core是自定義的,你可以定義lihch當然其他什麼都行。 接下來就回到了我們最初的問題,要將這些資料儲存起來。如下:
<script type="text/javascript">
	var callback = {
		login: [],
		req:[],
		lihch:[]
	}
	var core = {
		listen: function(id, handler) {
			callback[id].push(handler)
		},
		send: function(id, data) {
			var cbs = callback[id];
			for (var i = 0; i < cbs.length; i++) {
				cbs[i](data);
			}
		}
</script>


在listen裡: 我們將得到的方法(lihch方法,req方法,login方法等)新增(push)到數組裡。 在send裡: 我們遍歷listen中儲存的方法(比如(lihch方法))。並逐個觸發:lihch(data);

5.更好的方法

上面4方法中有兩個全域性變數:callback core 我們嘗試將其合併起來:
var core = {
		callback: {
			login: [],
			req:[],
			lihch:[]
		},
		listen: function(id, handler) {
			this.callback[id].push(handler)
		},
		send: function(id, data) {
			var cbs = callback[id];
			for (var i = 0; i < cbs.length; i++) {
				cbs	[i](data);
			}
		}
	}


這樣對面只暴露一個core,通過core.listen, core.send去執行。 這樣看似很美好,但是這個core.callback 誰都可以訪問到,在多人配合的情況下,難免出現類似於這樣的問題: core.callback = null; 好吧 ,那所有註冊的方法都失效了。為了保護它,我們繼續修改:
var core = (function() {
		var callback = {
			login: [],
			req:[],
			lihch:[]
		};
		return {
			listen: function(id, handler) {
			   callback[id].push(handler)
			},
			send: function(id, data) {
				var cbs = callback[id];
				for (var i = 0; i < cbs.length; i++) {
					cbs	[i](data);
				}
			}
		}
	})();


我們把他放進一個閉包裡面,只暴露listen和send這個兩個介面。callback是被包在core內部的變數,外部是訪問不到的。

但是這個時候還有一個問題: callback裡我們預設了lihch,login,req方法,但是我們又不知道頁面中到底會傳過來什麼用的訊息,那如果要監聽的是 lihouchun 呢, 有要修改上面的程式碼,在callback里加上   lihouchun: [];  顯然這樣也不是我們想要的,能不能讓他智慧點呢?
var core = (function() {

		var callback = {};
		
		return {
			listen: function(id, handler) {
				callback[id] = callback[id] || [];
				callback[id].push(handler)
			},
			send: function(id, data) {
				var cbs = callback[id];
				if (!cbs) return;
				for (var i = 0; i < cbs.length; i++) {
					cbs	[i](data);
				}
			}
		}
	})();


這樣,煩惱沒有了,listen的時候他會自動判斷新增,並且send的時候也做了處理。 這就是訊息機制,有了它,對程式碼的耦合性就大大降低,模組更加獨立,容錯性更強。