stevenjin 2024-08-17 17:39 采纳率: 97.3%
浏览 5
已结题

websocket断线重连写法的疑惑

1.声明的var heartCheck可以理解成一个类吗?为什么可以用heartCheck.start()的方法去调用?
2.为什么在heartCheck.start()方法中,要去调用close()方法关闭一下,这个有性能损耗吗?
3.网上这个断线重连方法靠谱吗?有没有更好的方法推荐?


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
    var lockReconnect = false;//避免重复连接
    var wsUrl = "ws://localhost:8080/websocket/111";        // websocket链接
    var ws;
    if ("WebSocket" in window) {
        function createWebSocket(){
            try {
                ws = new WebSocket(wsUrl);
                websocketInit();
            } catch (e) {
                console.log('catch');
                websocketReconnect(wsUrl);
            }
        }

        createWebSocket();            // 创建websocket

        function websocketInit () {
            // 建立 web socket 连接成功触发事件
            ws.onopen = function (evt) {
                onOpen(evt);
            };
            // 断开 web socket 连接成功触发事件
            ws.onclose = function (evt) {            
                websocketReconnect(wsUrl);
                onClose(evt);
            };
            // 接收服务端数据时触发事件
            ws.onmessage = function (evt) {
                onMessage(evt);
            };
            // 通信发生错误时触发
            ws.onerror = function (evt) {
                websocketReconnect(wsUrl);
                onError(evt);
            };
        };

        function onOpen(evt) {
            console.log("建立连接");
            //心跳检测重置
            heartCheck.start();
        }

        function onClose(evt) {
            console.log("连接已关闭...");
        }

       function onMessage(evt) {
            console.log('接收消息: ' + evt.data);
            var data = JSON.parse(evt.data);
            console.log(data);
            console.log(data.heart);
            if (data.hasOwnProperty("heart")) {// 存在key为heart
                    if (data.heart=="live"){// 心跳正常 再次执行
                        heartCheck.start();
                           console.log('心跳正常 再次执行心跳检测方法!');
                    }
                    return;
            }
        }
        
        function onError(evt) {
            console.log('通信错误:' + evt.data);
        }


        function websocketReconnect(url) {
            if (lockReconnect) {       // 是否已经执行重连
                return;
            };
            lockReconnect = true;
            //没连接上会一直重连,设置延迟避免请求过多
            tt && clearTimeout(tt);
            var tt = setTimeout(function () {
                createWebSocket(url);
                lockReconnect = false;
            }, 5000);
        }

        //心跳检测
        var heartCheck = {
            timeout: 30000,
            timeoutObj: null,
            serverTimeoutObj: null,
            start: function () {
                console.log('执行心跳检测');
                var self = this;
                this.timeoutObj && clearTimeout(this.timeoutObj);
                this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
                this.timeoutObj = setTimeout(function () {
                    //发送测试信息,后端收到后,返回一个消息,
                    ws.send("heart");
                    self.serverTimeoutObj = setTimeout(function () {
                        ws.close();
                    }, self.timeout);
                }, this.timeout)
            }
        }

       
    }else{
        alert("您的浏览器不支持websocket 请更换浏览器后重试!");
    } 

        </script>
</body>
</html>

  • 写回答

2条回答 默认 最新

  • GISer Liu 2024-08-17 19:12
    关注

    该回答引用自GPT-deepseek, 由博主 GISer Liu 编写:

    问题分析与解答

    1. 声明的 var heartCheck 可以理解成一个类吗?为什么可以用 heartCheck.start() 的方法去调用?

    var heartCheck 是一个对象字面量,而不是一个类。在 JavaScript 中,对象字面量是一种创建对象的方式,它包含一组键值对。在这个例子中,heartCheck 对象包含了一些属性和方法,例如 timeouttimeoutObjserverTimeoutObjstart 方法。

    虽然 heartCheck 不是类,但由于 JavaScript 的动态特性,我们可以像调用类的方法一样调用对象的方法。在这里,heartCheck.start() 就是调用 heartCheck 对象的 start 方法。

    2. 为什么在 heartCheck.start() 方法中,要去调用 close() 方法关闭一下,这个有性能损耗吗?

    heartCheck.start() 方法中调用 ws.close() 的目的是为了确保在心跳检测失败时,WebSocket 连接能够被关闭,从而触发 onclose 事件,进而进行重连操作。这是一种确保连接状态的机制。

    性能损耗方面,调用 ws.close() 本身是一个轻量级的操作,不会带来显著的性能损耗。但是,频繁的关闭和重连操作可能会对服务器和客户端的资源造成一定的压力,因此需要合理设置重连的延迟时间。

    3. 网上这个断线重连方法靠谱吗? 有没有更好的方法推荐?

    网上提供的断线重连方法在大多数情况下是靠谱的,但也有一些可以改进的地方。以下是一些改进建议:

    1. 优化重连逻辑:可以增加一些状态判断,避免不必要的重连操作。例如,可以在 onclose 事件中判断连接是否是正常关闭,如果是正常关闭则不进行重连。

    2. 心跳检测优化:可以增加心跳检测的灵活性,例如根据服务端的响应时间动态调整心跳间隔。

    3. 错误处理:增加更多的错误处理逻辑,例如在 onerror 事件中记录详细的错误信息,便于排查问题。

    以下是一个改进后的代码示例:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script>
        var lockReconnect = false; // 避免重复连接
        var wsUrl = "ws://localhost:8080/websocket/111"; // websocket链接
        var ws;
        if ("WebSocket" in window) {
            function createWebSocket() {
                try {
                    ws = new WebSocket(wsUrl);
                    websocketInit();
                } catch (e) {
                    console.log('catch');
                    websocketReconnect(wsUrl);
                }
            }
    
            createWebSocket(); // 创建websocket
    
            function websocketInit() {
                // 建立 web socket 连接成功触发事件
                ws.onopen = function (evt) {
                    onOpen(evt);
                };
                // 断开 web socket 连接成功触发事件
                ws.onclose = function (evt) {
                    onClose(evt);
                };
                // 接收服务端数据时触发事件
                ws.onmessage = function (evt) {
                    onMessage(evt);
                };
                // 通信发生错误时触发
                ws.onerror = function (evt) {
                    onError(evt);
                };
            }
    
            function onOpen(evt) {
                console.log("建立连接");
                // 心跳检测重置
                heartCheck.start();
            }
    
            function onClose(evt) {
                console.log("连接已关闭...");
                websocketReconnect(wsUrl);
            }
    
            function onMessage(evt) {
                console.log('接收消息: ' + evt.data);
                var data = JSON.parse(evt.data);
                console.log(data);
                console.log(data.heart);
                if (data.hasOwnProperty("heart")) { // 存在key为heart
                    if (data.heart == "live") { // 心跳正常 再次执行
                        heartCheck.start();
                        console.log('心跳正常 再次执行心跳检测方法!');
                    }
                    return;
                }
            }
    
            function onError(evt) {
                console.log('通信错误:' + evt.data);
                websocketReconnect(wsUrl);
            }
    
            function websocketReconnect(url) {
                if (lockReconnect) { // 是否已经执行重连
                    return;
                }
                lockReconnect = true;
                // 没连接上会一直重连,设置延迟避免请求过多
                tt && clearTimeout(tt);
                var tt = setTimeout(function () {
                    createWebSocket(url);
                    lockReconnect = false;
                }, 5000);
            }
    
            // 心跳检测
            var heartCheck = {
                timeout: 30000,
                timeoutObj: null,
                serverTimeoutObj: null,
                start: function () {
                    console.log('执行心跳检测');
                    var self = this;
                    this.timeoutObj && clearTimeout(this.timeoutObj);
                    this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
                    this.timeoutObj = setTimeout(function () {
                        // 发送测试信息,后端收到后,返回一个消息,
                        ws.send("heart");
                        self.serverTimeoutObj = setTimeout(function () {
                            ws.close();
                        }, self.timeout);
                    }, this.timeout)
                }
            }
        } else {
            alert("您的浏览器不支持websocket 请更换浏览器后重试!");
        }
        </script>
    </body>
    </html>
    

    在这个改进后的代码中,增加了一些状态判断和错误处理逻辑,使得断线重连机制更加健壮和灵活。

    如果该回答解决了您的问题,请采纳!如果没有,请私信联系或评论您的疑惑

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 8月25日
  • 已采纳回答 8月17日
  • 创建了问题 8月17日

悬赏问题

  • ¥15 网络分析设施点无法识别
  • ¥15 状态图的并发态问题咨询
  • ¥15 PFC3D,plot
  • ¥15 VAE模型编程报错无法解决
  • ¥100 基于SVM的信息粒化时序回归预测,有偿求解!
  • ¥15 物体组批优化问题-数学建模求解答
  • ¥15 微信原生小程序tabBar编译报错
  • ¥350 麦克风声源定位坐标不准
  • ¥15 apifox与swagger使用
  • ¥15 egg异步请求返回404的问题