业务背景
最近在做大屏数据可视化项目得时候,在思考项目交付和运行情况得时候,考虑到了需要在公司大屏显示器上面展示,突然想到了项目可能面临断网及其网速慢得情况下得一下展示问题,因此作为专栏进行这两个问题得讲解
问题一 WebSocket 在网络终端和重新联网后自动链接
知识点: 理解WebSocket心跳及重连机制
在使用websocket的过程中,有时候会遇到网络断开的情况,但是在网络断开的时候服务器端并没有触发onclose的事件。这样会有:服务器会继续向客户端发送多余的链接,并且这些数据还会丢失。所以就需要一种机制来检测客户端和服务端是否处于正常的链接状态。因此就有了websocket的心跳了。还有心跳,说明还活着,没有心跳说明已经挂掉了。
- 为什么叫心跳包呢?
它就像心跳一样每隔固定的时间发一次,来告诉服务器,我还活着。
- 心跳机制是?
心跳机制是每隔一段时间会向服务器发送一个数据包,告诉服务器自己还活着,同时客户端会确认服务器端是否还活着,如果还活着的话,就会回传一个数据包给客户端来确定服务器端也还活着,否则的话,有可能是网络断开连接了。需要重连~
那么需要怎么去实现它呢?如下所有代码:
let ws = null,
wsUrl = "ws://xxx/rest/api/websocket",
lockReconnect = false,
tt = null,
that = this;
function MonitorWebSocket(wsUrl){
this.timeout = 3000;
this.timeoutObj = null;
this.serverTimeoutObj= null;
try {
ws = new WebSocket(wsUrl);
this.init(wsUrl);
} catch(e) {
console.log('catch');
this.reconnect(wsUrl);
}
}
MonitorWebSocket.prototype.init = function (wsUrl) {
ws.onopen = () => {
//心跳检测重置
that.navigatorStatus()
// console.log("client:打开连接-心跳检测开启");
this.heartCheckStart();
};
ws.onmessage = e => {
// 拿到任何消息都说明当前连接是正常的
// console.info('onmessage---->接收到消息');
this.heartCheckStart();
that.list = JSON.parse(e.data).data;
that.list.todayData && that.$emit("changePointStatus",that.list.todayData)
};
ws.onclose = params => {
// console.log('链接关闭');
this.reconnect(wsUrl);
};
ws.onerror = function(e) {
// console.log('发生异常了');
this.reconnect(wsUrl);
};
}
MonitorWebSocket.prototype.reconnect = function(wsUrl) {
if(lockReconnect) {
return;
};
lockReconnect = true;
//没连接上会一直重连,设置延迟避免请求过多
tt && clearTimeout(tt);
tt = setTimeout(function () {
(function(){
// console.info("重新连接")
new MonitorWebSocket(wsUrl);
})()
lockReconnect = false;
}, 5000);
}
MonitorWebSocket.prototype.heartCheckStart = function() {
// console.log('心跳检测开始');
this.timeoutObj && clearTimeout(this.timeoutObj);
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
this.timeoutObj = setTimeout(function(){
//这里发送一个心跳,后端收到后,返回一个心跳消息,
// console.log('启动心跳');
ws.send("test");
this.serverTimeoutObj = setTimeout(function() {
ws.close();
}, this.timeout);
}, this.timeout)
}
let linkMarket = new MonitorWebSocket(wsUrl);
归纳与总结
实现心跳检测的思路是:每隔一段固定的时间,向服务器端发送一个ping数据,如果在正常的情况下,服务器会返回一个pong给客户端,如果客户端通过
onmessage事件能监听到的话,说明请求正常,这里我们使用了一个定时器,每隔3秒的情况下,如果是网络断开的情况下,在指定的时间内服务器端并没有返回心跳响应消息,因此服务器端断开了,因此这个时候我们使用ws.close关闭连接,在一段时间后(在不同的浏览器下,时间是不一样的,firefox响应更快),
可以通过 onclose事件监听到。因此在onclose事件内,我们可以调用 reconnect事件进行重连操作。
问题二 如何创建一个Javascript页面来检测用户的互联网速度并在页面上显示它?
知识点: 网速测试方法得核心思想
不管通过什么方式,一般都是通过下载一个文件,然后用文件的大小除以所耗时间,就是你的本地网络速度了。
这里介绍的是一个最常被使用的,又是最简单的方法。
let speed = {
status: 3,
},
that = this;
function Network () {
this.speedInterval = null;
this.networkInterval = null;
this.reNetworkInterval = null;
this.time = 5000;
this.speedStauts = null;
this.getConnectState = function() {
return navigator.onLine ? 1 : 0;
}
this.getSpeedStauts = function(){
return this.speedStauts;
}
}
// 网络速度检测
Network.prototype.startSpeed = function (){
window.clearInterval(this.speedInterval);
this.speedInterval = null;
let that = this;
if(this.getConnectState() == 1){
this.speedInterval = window.setInterval(function(){
let start = new Date().getTime();
if(that.getConnectState() == 1){
let img = document.getElementById("networkSpeedImage");
try{
img.src = "http://www.baidu.com/img/baidu_jgylogo3.gif?_t=" + new Date().getTime();
img.onload = function(){
let end = new Date().getTime();
let delta = end - start;
console.info("delta====>",delta)
if (delta > 200) {
console.info("凑活")
speed.status= 1;
} else if (delta > 100) {
speed.status = 2;
} else {
speed.status = 3;
}
console.info("statusSpeed====>",speed.status)
}
} catch {
speed.status = 0;
console.info("网络断开")
}
}else {
speed.status = 0;
console.info("网络断开2")
}
},this.time)
}else {
speed.status = 0;
console.info("网络断开1")
}
}
let netWork = new Network();
总结
通过创建img对象,设置onload监听回调,然后指定src, 一旦指定src,图片资源就会加载,完成时onload回调就会调用,我们可以根据时机分别标记start和end。
前端判断网速的方法及其优缺点
- img加载测速:借助img对象加载测算网速。优点:没有跨域带来的问题。缺点:(1)要自己测文件大小并提供参数fileSize,(2)文件必须为图片 (3)文件大小不能灵活控制
- Ajax测速: 通过Ajax测算网速。 优点: (1)不用提供文件大小参数,因为可以从response首部获得(2)测试的文件不一定要是图片,且数据量能灵活控制。缺点:跨域问题
- downlink测速: 通过navigator.connection.downlink读取网速。优点:不需要任何参数。缺点:1.兼容性很有问题,2.带宽查询不是实时的,具有分钟级别的时间间隔
已上都是可以三中方法都可以实现,大家可以考虑个子得项目进行合理得选择