1

创建一个websocket.js(@/utils/websockets)
自定义插件

/**
 * 发起websocket请求函数
 * @param {object} wsObj  - ws对象
 * @param {string} type  - 操作websocket:销毁close、创建create
 * @param {number} timeout  - 心跳间隔时长,默认5000ms
 * @param sendHeartBeat  - 以心跳,内容体区分string、object
 * @param {function} msgCallback  - 接收到ws数据,对数据进行处理的回调函数
 * @param {function} reCallback  - ws每次重连时,暴露对外的回调函数
 */
import { Message } from "element-ui";

export function websocketCommand(
  wsObj,
  type,
  timeout = 5000,
  sendHeartBeat,
  msgCallback,
  reCallback
) {
  let wsDestroy = type === "close"; //  销毁标志
  let lockReconnect = false; // 是否真正建立连接
  let timeoutObj = null; // 心跳倒计时
  let serverTimeoutObj = null; // 服务器心跳倒计时
  let timeoutnum = null; // 断开 重连倒计时

  // 若type传入close,则意图销毁websocket
  if (type === "close") {
    clearTimeout(timeoutObj);
    clearTimeout(serverTimeoutObj);
    onClose();
  }
  // 若type传入create,则意图新建websocket,需初始化ws并发送心跳
  if (type === "create") {
    initWebsocket();
    websocketSend();
  }

  function initWebsocket() {
    if (typeof WebSocket === "undefined") {
      Message.warning("您的浏览器不支持WebSocket,无法获取数据");
      return false;
    }
    wsObj.onmessage = function (e) {
      onMessage(e);
    };
    wsObj.onopen = function () {
      onOpen();
    };
    wsObj.onerror = function () {
      onError();
    };
    wsObj.onclose = function () {
      onClose();
    };
  }

  function websocketSend() {
    // 加延迟是为了尽量让ws连接状态变为OPEN
    setTimeout(() => {
      // 添加状态判断,当为OPEN时,发送消息
      if (wsObj.readyState === wsObj.OPEN) {
        if (typeof sendHeartBeat == "string") {
          // 若发送基本类型数据作为心跳,如字符串,直接将参数发送给服务端
          wsObj.send(sendHeartBeat);
        } else {
          // 若发送复杂类型数据作为心跳,如对象,则以回调方式暴露出去(得以支持动态数据)
          sendHeartBeat();
        }
      }
    }, 500);
  }

  function onMessage(evt) {
    try {
      var received_msg = evt && JSON.parse(evt.data);
    } catch (e) {
      // 转换出错,抛出异常
      return
    }
    msgCallback(received_msg);
    // 收到服务器信息, 重置服务器心跳
    start();
  }

  function onError() {
    // 断网重连机制
    if (!wsDestroy) {
      reconnect();
    }
  }

  function onOpen() {
    // 连接成功向服务器发送信息,并开启心跳
    websocketSend();
    start();
  }

  function reconnect() {
    // 避免重复建立连接
    if (lockReconnect) {
      return;
    }
    lockReconnect = true;
    // 没连接上会一直重连,设置延迟避免请求过多
    timeoutnum && clearTimeout(timeoutnum);
    timeoutnum = setTimeout(function () {
      // 重连
      // initWebsocket();
      // 若重连后有需额外处理的逻辑,通过reCallback()回调暴露出去
      reCallback?.();
      lockReconnect = false;
    }, timeout);
  }

  function start() {
    // 清计时器
    timeoutObj && clearTimeout(timeoutObj);
    serverTimeoutObj && clearTimeout(serverTimeoutObj);
    // 开启心跳
    timeoutObj = setTimeout(function () {
      if (wsObj.readyState == 1) {
        // 如果连接正常,发送心跳(服务端收到后会返回一条消息)
        websocketSend();
      } else {
        // 否则重连
        reconnect();
      }
      // 超时关闭
      serverTimeoutObj = setTimeout(function () {
        wsObj.close();
      }, timeout);
    }, timeout);
  }

  function onClose() {
    if (!wsDestroy) {
      // 重连机制
      reconnect();
    } else if (wsObj.readyState == 1) {
      // 如果ws连接正常,则清计时器、断开连接
      clearTimeout(timeoutObj);
      clearTimeout(serverTimeoutObj);
      wsObj?.close?.();
    }
  }
}

接下来进行引用【在vue文件中】:

// 引入websocket
import { websocketCommand } from "@utils/websocket.js";

在vue文件中使用:

  created() {
    this.createWs();
  },

写在methods中:

    //  ws连接成功,后台返回的ws数据
    receiveMsg(data) {
      // 收到服务端发送的数据后,需要处理的逻辑
      // 根据业务需求进行逻辑处理
     ...
    },
    // 建立连接、发起ws请求,以心跳方式,向服务端发送数据
    createWs() {
      if (this.wsObj) {
        websocketCommand(this.wsObj, "close");
        this.wsObj = null;
      }
      this.wsObj = new WebSocket(
        process.env.VUE_APP_WEBSOCKET_API +
          "/socket/marketData?token=" +
          this.token
      );
      this.loading = true;
      // 若为对象类型,以回调方式发送
      websocketCommand(
        this.wsObj,
        "create",
        5000,
        this.sendHeartBeat,
        this.receiveMsg,
        this.reconnectWs
      );
    },
    // 断网重连,需要处理的逻辑
    reconnectWs() {
      if (this.wsObj) {
        this.createWs();
        // 业务代码 若交易序列不为空 则需要重新发送请求
        if (this.queryParams.type != null) {
          this.handleCodeChange();
        }
      }
    },
    // websocket发送请求
    handleCodeChange() {
      let sendObj = { sequenceCode: this.queryParams.type };
      this.wsObj.send(JSON.stringify(sendObj));
    },
    // 以回调方式向服务端发送(对象类型的)心跳
    sendHeartBeat() {},
// 销毁websocket
  destroyed() {
    websocketCommand(this.wsObj, "close");
    this.wsObj = null;
  },

阿酒在看云
4 声望1 粉丝

晓看天色暮看云