JavaScript 踩坑 WebSocket

踩坑1:websocket异步执行导致执行多次

目的:
想编写一个websocket自动重连功能
方法:
当连接断开时,利用.onclose创建定时任务,定时尝试创建websocket连接。
异常现象:
定时任务间隔在2秒以内,当网络通畅后,最后有多个websocket同时建立。
原因:
定时任务创建websocket是异步执行,但没有在任务内判断上一个websocket重连是否已执行结束。
websocket异步导致任务执行后没有立即尝试连接websocket,而是等了2秒多才执行,推迟到了下一个2秒后的定时任务执行周期内,导致最后网络畅通时多个websocket都尝试创建并成功。
解决:
尝试重连的任务内使用options.ws.readyState判断上次尝试是否结束且失败。
正常代码:

// 初始化
Usocket.prototype.init = function() {
    let options = this.options; // 此方法所属类的属性,当做普通对象变量即可。
    if ( 'WebSocket' in window) {
        let heartbeat_id = undefined;
        let offline_recover_id = undefined;
        let create_socket = () => { // 创建websocket连接的匿名函数
            console.log("执行create_socket");
            options.ws = new WebSocket(options.socket_url);
            options.ws.onopen = () => {
                console.log("已建立连接");
                if (offline_recover_id === undefined) {
                    console.log("断线重连未开启");
                } else {
                    clearInterval(offline_recover_id);
                    offline_recover_id = undefined;
                }
                // 定时心跳
                let heartbeat_i = 0;
                heartbeat_id = setInterval(function () {
                    console.log("心跳包发送:" + heartbeat_i++);
                    options.ws.send("");
                }, options.heartbeat_time);
                options.onopen();
            };
            options.ws.onmessage = options.onmessage;
            options.ws.onclose = () => {
                clearInterval(heartbeat_id);
                options.onclose();
                if (offline_recover_id === undefined) {
                    console.log("创建offline_recover_id");
                    offline_recover_id = setInterval(function () {
                        console.log("开始执行定时器函数");
                        if (options.ws.readyState == options.ws.CLOSED) {
                            create_socket();
                        } else {
                            console.log("ws未关闭,本次不执行重连");
                        }
                    }, options.offline_recover_time);
                }
            }
            options.ws.onerror = () => {
                options.onerror;
            }
        };
        create_socket();
    } else {
        console.log('您的浏览器不支持WebSocket');
    }
};

踩坑2:同一浏览器内,websocket后的alert会阻塞其他页面的js执行

测试了websocket.onmessage接收消息,setInterval任务,估计是阻塞全浏览器js。
测试代码:

<html>
   <script type="text/javascript">
   if ( 'WebSocket' in window) {
      var ws = new WebSocket("ws://127.0.0.1:2000");
      
      console.log(".onopen设置前");
      ws.onopen = function()
      {
         // ws.send("js的webscoket数据");
         console.log("执行.onopen,scoket开始建立连接...");
      };
      console.log(".onopen设置后");
      
      ws.onmessage = function (evt)
      {
         var received_msg = evt.data;
         console.log('js接收到:'+received_msg);
         alert('js接收到:'+received_msg); // 此行会触发alert阻塞其他页面js,也可用于打开多个此页面时来验证阻塞(此页面A触发时,此页面B被阻塞)
      };
      
      ws.onclose = function()
      {
         alert('close');
         console.log("连已关闭...");
      };
      
      setInterval(function () {
         console.log("心跳包发送");
         ws.send("");  
      }, 5000);
      setInterval(function () { // 此行测试阻塞setInterval
      let a  = 0;
         console.log(a++);
      })
   } else {
      alert('您的浏览器不支持WebSocket');
   }
   function test_webSocket()
   {
      let user = {
         'username' : 'xiaoming',
         'key' : 'zdkj-123456',
         'action' : 'broadcast',
         'data' : {
            'msg' : 'js广播测试数据'
         }
      };
      // ws.send("js的webscoket数据");
      //console.log(JSON.stringify(user));
      ws.send(JSON.stringify(user));         
   }
   </script>
   <body>
      <div id="">
         <a href="javascript:test_webSocket()">发送 WebSocket请求</a>
      </div>
   </body>
</html>
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值