Appearance
介绍
一个通用的 websocket 封装实例,包括 Api 的回调,消息发送,连接关闭。连接出错重连,重连次数限制,重连超时停止操作等
实现
javascript
function setDefaultConfig(defaultConfig, originalConfig) {
var defaultKeys = Object.keys(defaultConfig);
var originalKeys = Object.keys(originalConfig);
if (typeof $ == 'undefined') {
console.error('请在jQuery之后引用此js');
return;
}
var returnConfig = $.extend(true, {}, originalConfig);
for (var key in defaultConfig) {
if (defaultConfig.hasOwnProperty(key)) {
var element = defaultConfig[key];
if ($.inArray(key, originalKeys) == -1) {
switch ($.type(element)) {
case 'string':
case 'number':
case 'boolean':
case 'function':
returnConfig[key] = element;
break;
case 'array':
returnConfig[key] = $.extend(true, [], element);
break;
case 'object':
returnConfig[key] = $.extend(true, {}, element);
break;
case 'undefined':
case 'null':
break;
default:
break;
}
}
}
}
return returnConfig;
}
/**
*
* @param {配置} originalConfig
* @param {string} originalConfig.url - 链接的url
* @param {string} originalConfig.host - 主机名 有url则不传,url需要有主机名
* @param {string} originalConfig.protocols - 链接使用的协议 ws wss 默认根据location进行判断 http ws or htps wss 有url则不传,url需要有协议
* @param {string} originalConfig.port - 例 ':8080' 端口号 有url则不传,url需要有端口
* @param {string} originalConfig.message - 连接成功后默认发送的数据,并且在执行send如果没有传递参数,则默认发送该值
* @param {Function} originalConfig.onopen - 连接成功后触发发
* @param {Function} originalConfig.onmessage - 接收到消息触发
* @param {Function} originalConfig.onclose - 关闭后触发
* @param {Function} originalConfig.onbeforeclose - 关闭之前触发
* @param {Function} originalConfig.onerror - 发生错误后触发
*/
var wbst = (function (window, $) {
//重连开始时间
var reConnectBeginTime;
//重连计数
var reConnectNum = 1;
//重连次数限定
var limitReConnectNum = 3;
//重连timer
var reConnectTimer;
// 构造函数
function websocket(originalConfig) {
/**
* Wbst实例 close //关闭连接
* send //发送消息
*/
//默认配置参数
var defaultConfig = {
protocol: location.protocol == 'http:' ? 'ws:' : 'wss:',
port: location.port,
ws: null,
timeout: 5000,
onopen: function () {},
onmessage: function () {},
onclose: function () {},
onerror: function () {},
onbeforeclose: function () {},
};
//主机名
var host = location.hostName;
//路径
var pathName = location.pathname;
//是否心跳状态,为false不可操作,等待重连
this.isHeartFlat = false;
//重连状态
this.isReconnect = false;
originalConfig
? (this.config = setDefaultConfig(defaultConfig, originalConfig))
: (this.config = defaultConfig);
this.config.protocol.indexOf(':') == -1 ? (config.protocol += ':') : '';
//如果没有定义url,则拼接url
if (typeof this.config.url == 'undefined') {
this.config.url = this.config.protocol + '//' + host + ':' + this.config.port + pathName;
}
//发送消息函数
this.send = function (message) {
if (!this.ws) {
console.error('websocket链接已关闭', this);
return;
}
//如果没有传值,则默认发送配置的默认消息
if (typeof message == 'undefined' && typeof this.config.message != 'undefined') {
message = this.config.message;
}
//判断心跳检测,连接是否存在或已连接
if (!this.isHeartFlat) {
// console.error("websocket未连接或出现故障或已断开,正在重新发送...");
var _self = this;
// var timeout = setTimeout(function () {}, 0);
var timeout = setTimeout(function () {
var interval = setInterval(function () {
if (_self.ws.readyState === 1) {
clearTimeout(timeout);
clearInterval(interval);
timeout = null;
interval = null;
_self.send(message);
// console.log("websocket已发送请求");
} else {
clearTimeout(timeout);
clearInterval(interval);
console.error('websocket链接异常', this);
}
}, 100);
}, 0);
return;
} else {
this.ws.send(message);
}
};
//关闭连接
this.close = function () {
if (!this.ws) {
console.error('链接已关闭');
return;
}
this.config.onbeforeclose(this.config, this.ws);
this.ws.close();
};
this.init();
}
//初始化
websocket.prototype.init = function () {
var _self = this;
window.WebSocket = window.WebSocket || window.MozWebSocket;
if (!window.WebSocket) {
console.error('浏览器不支持WebSocket');
return;
}
var ws = new WebSocket(this.config.url);
ws.onopen = function (e) {
_self.onopen(e);
};
ws.onmessage = function (e) {
_self.onmessage(e);
};
ws.onclose = function (e) {
_self.onclose(e);
};
ws.onerror = function (e) {
_self.onerror(e);
};
this.ws = ws;
return;
};
//连接成功
websocket.prototype.onopen = function (e) {
this.isHeartFlat = true;
this.config.onopen(e);
if (typeof this.config.message != 'undefined') {
this.ws.send(this.config.message);
}
};
//接收消息回调
websocket.prototype.onmessage = function (e) {
this.config.onmessage(e);
};
//连接出错回调,默认执行重连操作
websocket.prototype.onerror = function (e) {
var _self = this;
//心跳值为false
this.isHeartFlat = false;
this.config.onerror(e);
if (reConnectNum <= limitReConnectNum) {
//开始重连
console.error('WebSocket连接出错,正在重连...');
clearTimeout(reConnectTimer);
reConnectTimer = setTimeout(function () {
if (reConnectNum == 1) {
reConnectBeginTime = new Date();
}
console.log('尝试第' + reConnectNum + '次重连');
_self.isReconnect = true;
_self.reConnect();
//如果心跳值为true,则重连成功
if (_self.isHeartFlat) {
clearTimeout(reConnectTimer);
reConnectTimer = null;
}
}, 2000);
} else {
console.error('重连次数超出设定值,不再重连,请检查配置项');
}
};
//关闭回调
websocket.prototype.onclose = function (e) {
this.isHeartFlat = false;
this.config.onclose(e);
};
//重连操作
websocket.prototype.reConnect = function () {
//如果没有触发重连操作,则不执行
if (!this.isReconnect) return;
//判断重连超时,若超时,则不再重连
if (new Date() - reConnectBeginTime > this.config.timeout) {
console.error('websocket重连超时');
this.isReconnect = false;
//清除重连延时器
clearTimeout(reConnectTimer);
reConnectTimer = null;
return;
}
//开始重连
var _self = this;
//重连计数器
reConnectNum++;
_self.init();
};
return websocket;
})(window, jQuery);