之前有一次為了做一個類似於谷歌、百度的輸入提示,扒了百度的代碼(現在的地址http://www.baidu.com/js/bdsug.js?v=1.0.3.0,格式化一下再看)研究了一番,發現百度的消息機制簡潔有效,之後根據它寫了一套自己的消息機制,應用在其後的一個web ajax聊天程序中。之後和朋友討論後,完善了一下,做了一個類似於event的事件機制(在普通object上模擬dom事件的自定義事件),現在基於類似的機制應用到了目前的ERP項目中實現了一套js插件機制、iframe通信機制等等(我很慚愧,太懶了,沒有學習使用現成的js框架,自己又造了個輪子),現在勤勞一下,拿出來讓大家樂呵樂呵,本人主攻後台開發,js只是業余愛好,歡迎指正。
先說說百度的代碼,核心的東西,如下:
baidu Code
var J = (function(){ function C(b){ var Z = this.__MSG_QS__; if (!Z[b]) { Z[b] = [] } for (var a = 1, X = arguments.length, Y; a < X; a++) { Z[b].push(arguments[a]) } } function G(Y){ var Z = this.__MSG_QS__[Y.type]; if (Z == null) { return } for (var a = 0, X = Z.length; a < X; a++) { Z[a].rm(Y) } } return { ini: function(X){ X.__MSG_QS__ = {}; X.on = C; X.dm = G; return X } } })();代碼是經過壓縮處理的,我比較懶,不亂猜測其原名了。
這算是一個很輕量級的消息機制,執行這段代碼,獲得了J這個對象,可以從代碼看出J={ini:function(){……}}
研究一下ini的函數:
View Code
function(X){ X.__MSG_QS__ = {}; X.on = C; X.dm = G; return X }它的作用就是為一個對象綁定 :
一個屬性__MSG_QS__
兩個函數on(=C),dm(=G)
__MSG_QS__的作用是來存儲消息隊列,它是一個json對象,所以可以存儲多個消息隊列類似於這樣的格式{"click":[],"blur":[]}
on就是增加監聽者
View Code
function C(b){ var Z = this.__MSG_QS__; if (!Z[b]) { Z[b] = [] } for (var a = 1, X = arguments.length, Y; a < X; a++) { Z[b].push(arguments[a]) } }負責將監聽消息的對象加入__MSG_QS__中
dm是觸發消息的
View Code
function G(Y){ var Z = this.__MSG_QS__[Y.type]; if (Z == null) { return } for (var a = 0, X = Z.length; a < X; a++) { Z[a].rm(Y) } }如果消息偵聽隊列存在,dm會循環調用監聽者的rm函數
寫一個簡單的示例:
View Code
var dataLayer = J.ini({ getData: function(){ this.dm({type:"data",data:1}) }})var controlLayer=J.ini({ rm:function(Y) { switch(Y.type) { case "data": Y.data++; this.dm({type:"show",data:Y.data}); } }})var viewLayer=J.ini({ rm:function(Y) { switch(Y.type) { case "show": alert(Y.data); } } });dataLayer.on("data",controlLayer);controlLayer.on("show",viewLayer);dataLayer.getData();dataLayer.getData()會產生一個數據(可以想象是服務器傳回的),並觸發“data”消息
controlLayer對象收到後,處理數據(+1),然後觸發“show“消息
viewLayer對象收到後,只是簡單將數據彈出
這只是簡單的一個示例,你可以把dataLayer,controlLayer,viewLayer當做是獨立的js文件(模塊),代碼
View Code
dataLayer.on("data",controlLayer);controlLayer.on("show",viewLayer);dataLayer.getData();看做是在頁面中(或某個main.js)中,那麼這些模塊之間就很容易的實現消息傳遞,並且它是低耦合的
舉個例子,比如我們不喜歡alert,希望它在頁面元素中顯示,那麼增加一個模塊代碼:
View Code
var viewLayer1=J.ini({ rm:function(Y) { switch(Y.type) { case "show": document.getElementById("show").innerHTML=Y.data; } } });修改一下所謂main.js,如下
View Code
dataLayer.on("data",controlLayer);controlLayer.on("show",viewLayer1);dataLayer.getData();是不是很靈活,dataLayer,controlLayer的代碼完全不用修改(假設它們是獨立的js文件,或很多個相關js文件,或者很長很長的一段代碼,你會感到很高興)
消息機制的另外一個特點,多播,比如需求改了,要求又要有alert,又要在頁面顯示,這下你會更高興,修改一下代碼
View Code
dataLayer.on("data",controlLayer);controlLayer.on("show",viewLayer,viewLayer1);dataLayer.getData();
消息也可以有很多的源頭,例如:
View Code
var dataLayer1 = J.ini({ getData: function(){ this.dm({type:"data",data:10}) }})//************省略dataLayer.on("data",controlLayer);dataLayer1.on("data",controlLayer);controlLayer.on("show",viewLayer,viewLayer1);dataLayer.getData();dataLayer1.getData();從這些示例,我們可以看出消息機制的靈活性
補充:(re:AlexTiffy )傳播知識的工作不好做……自以為懂了不算真的懂,得要講的明白,講明白好難……。
其實具體的原理可以參考觀察者模式。
所謂消息,或者也可以稱之為事件,基本的思想就是,當對象發生變化的時候,就通知關注這個變化的對象,微博很流行,關注這個詞相信大家應該不陌生。
概況一下消息的幾個概念:
1. 關注(也可以說是監聽)
2. 消息,是我們的數據,也是信息載體。它包含一些我們關注的信息。
3. 觸發消息,把數據打包成一個消息,然後發送給每一位關注者
4. 接受並處理消息
舉個例子
假設我們現在有兩個對象her(一位美女),一個me(偶了),這位美女經常發個圖、說說話什麼的,me現在要關注她,就得使用她頁面上關注功能(on),可是你不想關注她說什麼,只想看看她的美圖
就是她發美圖了,me就會收到。怎麼實現?
首先使用her.on("pic",me) 關注她發圖的消息,這個關注操作會把me放到her的圖片關注者列表中。(列表就是__MSG_QS__["pic"],美女還有很多的其他類型的消息 比如__MSG_QS__["say"]等等)
美女每次發圖片,就會調用her.dm({type:'pic',picUrl:''});然後消息機制就會把{type:'pic',picUrl:''}信息傳給圖片關注者列表中每一位。
me這邊必須要有一個方法來收這個圖片消息,就是
me.rm(obj)
首先呢,我們rm會收到很多消息,它就像信箱,什麼信件都放在裡邊,我們首先要判斷一下收到的消息是什麼?
obj.type
如果obj.type=='pic',然後我自己看著辦了……
總結:
消息機制的優勢:
1. 低耦合性 模塊之間通過消息傳輸數據,這樣基本上沒有對其他模塊的調用
2. 靈活性 在使用的時候才組裝模塊,可以根據需求任意組裝模塊