132 lines
3.5 KiB
JavaScript
132 lines
3.5 KiB
JavaScript
function SocketHandler(url) {
|
||
// 基于H5原生api
|
||
this.ws = new WebSocket(url);
|
||
// 定义一个信号发射塔,用于发送事件
|
||
this.tower = document.createElement('div');
|
||
}
|
||
|
||
SocketHandler.prototype = {
|
||
// 订阅频道
|
||
channels : {},
|
||
// 反应堆(用于收集和分发socket的响应)
|
||
reactions : {},
|
||
// 缓存监听事件
|
||
events : [],
|
||
// 获取当前时间
|
||
nowTime : function() {
|
||
return new Date().getTime();
|
||
},
|
||
// 打开socket连接
|
||
open : function(heartbeatTimeout) {
|
||
this.ws.onopen = function(){
|
||
var heartbeatSendInterval = heartbeatTimeout / 2;
|
||
this.lastSubscribeTime = this.nowTime();
|
||
this.pingIntervalId = setInterval(function(){
|
||
var iv = this.nowTime() - this.lastSubscribeTime;
|
||
// 超过一定时间自动与后台ping、pong 单位:秒
|
||
if ((heartbeatSendInterval + iv) >= heartbeatTimeout) {
|
||
this.send('ping');
|
||
}
|
||
}.bind(this), heartbeatSendInterval);
|
||
}.bind(this);
|
||
},
|
||
|
||
// 创建自定义事件
|
||
createEvent : function(event, detail){
|
||
var evt = document.createEvent('CustomEvent');
|
||
evt.initCustomEvent(event, false, false, detail);
|
||
return evt;
|
||
},
|
||
|
||
// 打开socket连接
|
||
connect: function(heartbeatTimeout) {
|
||
this.open(heartbeatTimeout);
|
||
this.message();
|
||
this.close();
|
||
},
|
||
|
||
// 订阅消息 ch 为订阅的频道 id 为订阅唯一标识
|
||
subscribe : function(ch, id, token) {
|
||
if(this.ws.readyState == 1) {
|
||
var obj = {};
|
||
if(ch) {
|
||
obj.sub = ch;
|
||
obj.id = id;
|
||
if(token) obj.authorization = token;
|
||
if(this.channels.hasOwnProperty(id)) {
|
||
this.unsubscribe.apply(this, Object.values(this.channels[id]));
|
||
}
|
||
this.channels[id] = obj;
|
||
this.reactions[ch] = this.createEvent(id);
|
||
this.send(obj);
|
||
}
|
||
}
|
||
},
|
||
|
||
// 监听订阅结果
|
||
on : function(id, callback) {
|
||
var handler = function(e) {
|
||
if(callback) callback(e.data, e);
|
||
};
|
||
this.tower.addEventListener(id, handler);
|
||
var key = id + '_' + this.nowTime();
|
||
this.events.push({key : key, handler: handler});
|
||
},
|
||
|
||
// 取消订阅
|
||
unsubscribe : function(ch, id, token) {
|
||
if(this.ws.readyState == 1) {
|
||
var obj = {};
|
||
if(ch) {
|
||
obj.cancel = ch;
|
||
obj.id = id;
|
||
if(token) obj.authorization = token;
|
||
if(this.channels.hasOwnProperty(id)) {
|
||
delete this.channels[id];
|
||
delete this.reactions[ch];
|
||
}
|
||
this.events = this.events.filter(function(v){
|
||
if(v.key.indexOf(id) !== -1) {
|
||
// 失效ID解除监听
|
||
this.tower.removeEventListener(id, v.handler);
|
||
}else{
|
||
return v;
|
||
}
|
||
}.bind(this));
|
||
this.send(obj);
|
||
}
|
||
}
|
||
},
|
||
|
||
send : function(data){
|
||
if(typeof data === 'object') {
|
||
data = JSON.stringify(data);
|
||
}
|
||
this.ws.send(data);
|
||
},
|
||
|
||
message : function() {
|
||
this.ws.onmessage = function(evt){
|
||
var data = evt.data;
|
||
this.lastSubscribeTime = this.nowTime();
|
||
if(data) {
|
||
if(data !== 'pong') data = JSON.parse(data);
|
||
if(typeof data === 'object' && data.hasOwnProperty('ch')) {
|
||
var e = this.reactions[data.ch];
|
||
if(e) {
|
||
e.data = data;
|
||
this.tower.dispatchEvent(e);
|
||
}
|
||
}
|
||
}
|
||
}.bind(this);
|
||
},
|
||
|
||
close : function(callback) {
|
||
this.ws.onclose = function(evt){
|
||
clearInterval(this.pingIntervalId);
|
||
if(callback) callback(evt, this.ws);
|
||
}.bind(this);
|
||
}
|
||
};
|