基于事件驱动的前端通信框架(封装socket.io)
socket.io的使用可以很轻松的实现websockets,兼容所有浏览器,提供实时的用户体验,并且为程序员提供客户端与服务端一致的编程体验。但是在使用socket.io的过程中,由于业务需求需要同时发起几个请求,并等待数据返回调用相对应的回调函数执行,那么在数据返回时,你如何知道这个数据是要用于那个回调函数的,也就是说该去执行那个回调函数来处理返回来的数据?在使用AS过程中发现,AS的事件机制是一个很灵活的东西,你可以自定义多个事件监听,然后在派发事件的时候会根据你派发的事件调用相对应的回调函数。那么如何把这一东西用到socket.io中呢,就是如果发送某个请求时同事让它与它需要回调的函数关联,那么在请求返回数据的时候我就可以根据这个关联找到它要回调的函数并执行。就像AS的事件机制一样,你为某个事件添加了监听,那么当这个事件派发出来的时候就会去调用相对应的回调函数。为了实现这一目的我做了以下几个东西。
首先是Event类:
/**
* 事件类
*/
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;
}
};
接着是各个不同的数据请求,例如增删改查命令
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类型调用对应的回调函数。