socket.io的使用能夠很輕鬆的實現websockets,兼容全部瀏覽器,提供實時的用戶體驗,而且爲程序員提供客戶端與服務端一致的編程體驗。可是在使用socket.io的過程當中,因爲業務需求須要同時發起幾個請求,並等待數據返回調用相對應的回調函數執行,那麼在數據返回時,你如何知道這個數據是要用於那個回調函數的,也就是說該去執行那個回調函數來處理返回來的數據?在使用AS過程當中發現,AS的事件機制是一個很靈活的東西,你能夠自定義多個事件監聽,而後在派發事件的時候會根據你派發的事件調用相對應的回調函數。那麼如何把這一東西用到socket.io中呢,就是若是發送某個請求時同事讓它與它須要回調的函數關聯,那麼在請求返回數據的時候我就能夠根據這個關聯找到它要回調的函數並執行。就像AS的事件機制同樣,你爲某個事件添加了監聽,那麼當這個事件派發出來的時候就會去調用相對應的回調函數。爲了實現這一目的我作了如下幾個東西。程序員
首先是Event類:web
/** * 事件類 */
var Event = function (type, data,cancelable) { this.cancelable = cancelable; //是否取消傳遞
this.type = type; //類型
this.data = data; // 數據
/// <summary>
/// 複製
/// </summary>
/// <returns type="Event">複製後的元素</returns>
this.clone = function() { var that = new Event(); that.cancelable = this.cancelable; that.type = this.type; that.data = this.data; return that; }; this.toString = function() { return "Event( type: " + this.type + ", cancelable: " + this.cancelable + this.eventPhase + ")"; }; };
接着是EventListener :
/** * 事件監聽類 * @param listener 監聽回調函數 * @param priority 優先級 */
var EventListener = function (listener,priority) { if (typeof(arguments[0]) != "function") { throw new Error("必須指明listener"); } this.listener = listener; this.priority = priority?priority:0; };
再接着是EventManager,用於關聯事件和它對應的回調 :編程
var EventManager = { eventListeners : [], /// <summary>
/// 添加事件處理函數
/// </summary>
/// <param name="type">類型</param>
/// <param name="listener">處理函數</param>
/// <param name="priority">優先級,默認爲0</param>
addEventListener : function (type, listener, priority) { if (typeof (arguments[1]) != "function") { throw new Error("必須指明type和listener"); } if (!this.eventListeners[type]) { this.eventListeners[type] = []; } var index = this.eventListeners[type].length; console.log(type + "監聽個數:" + index); //防止重複監聽
for (var i = 0; i < index; i++) { var temp = this.eventListeners[type][i]; if (temp.listener == listener) { return; } } var eventListener = new EventListener(listener, priority); this.eventListeners[type].push(eventListener); this.eventListeners[type].sort(function (a, b) { return a.priority - b.priority; }); }, /// <summary>
/// 移除監聽器
/// </summary>
/// <param name="type">類型</param>
/// <param name="listener">監聽器</param>
removeEventListener : function (type, listener) { var len = arguments.length; if (len < 2) { throw new Error("必須指定type 與 listener"); } if (!this.eventListeners[type]) { return; } var index = this.eventListeners[type].length; //若是數組長度爲0,刪掉整個數組
if (index == 0) { var lisIndex = this.eventListeners.length; for (var i = 0; i < lisIndex; i++) { if (type == this.eventListeners[i]) { this.eventListeners.splice(i, 1); } } } else { for (var j = 0; j < index; j++) { var temp = this.eventListeners[type][0]; if (temp.listener == listener) { this.eventListeners[type].splice(0, 1); } } } }, /// <summary>
/// 分派一個事件
/// </summary>
/// <param name="event">事件</param>
dispatchEvent : function (event) { // 若是event不是一個Event類,則默認是字符串,做爲事件標識建立一個新的Event(event)
event = (typeof (event) == "string") ? new Event(event) : event; if (!this.eventListeners[event.type]) { return; } var index = this.eventListeners[event.type].length; for (var k = 0; k < index; k++) { var temp = this.eventListeners[event.type][k]; if (temp.listener) { if (!event.cancelable) { temp.listener(event); } else { continue; } } } }, /// <summary>
/// 判斷是否具備該事件的處理器
/// </summary>
/// <param name="type">事件類型</param>
/// <returns type="boolean">判斷是否具備該事件的處理器</returns>
hasEventListener : function (type) { return this.eventListeners[type] && this.eventListeners[type].length > 0; } };
接着是各個不一樣的數據請求,例如增刪改查命令json
var RequestManager = { sendData: function (eventType, params, listener, priority) { EventManager.addEventListener(eventType, listener, priority); console.log("發包,事件:" + eventType); var json = { eventType: eventType, parameters: params }; SocketManager._instance.json.send(json); }, readData: function (data) { var evt = new Event(); evt.type = data.eventType; evt.data = data; EventManager.dispatchEvent(evt); } };
再來是SocketManager,對socket.io進行封裝,這裏至關因而單例的實現,保證了應用中只存在一個socket:數組
var SocketManager = { _instance: null, connect: function (ip,port) { if (_instance) { return; } _instance = io.connect("http://" + ip + ":" + port); _instance.on("connect", function (data) { console.log("Connected to Server"); }); _instance.on("message", function (data) { console.log("readData:" + data); RequestManager.readData(data); }); _instance.on('reconnect', function () { console.log("reconnect to Server"); }); } };
使用起來也很是簡單,經過調用SocketManager.connect(ip,port);便可實例化一個socket,再來經過RequestManager.sendData("getData1", params, getData1Handler, 0);既可完成數據訪問,但同時有不少個請求時,如RequestManager.sendData("getData2", params, getData2Handler, 1);RequestManager.sendData("getData3", params, getData3Handler, 2);一樣能夠根據數據的eventType類型調用對應的回調函數。瀏覽器