發佈 訂閱 消息系統(一)

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的時候也做了處理。
 
這就是消息機制,有了它,對代碼的耦合性就大大降低,模塊更加獨立,容錯性更強。
 
   
此文後續: 觀察者模式和發佈訂閱模式。 鏈接:  https://blog.csdn.net/lihchweb/article/details/104001403
 
 
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章