记录一次websocket封装

JavaScript1 个月前0117

在一个应用中,websocket一般都是以单例形式存在的,即在整个应用中,websocket实例始终保持唯一。但有时我们要用到websocket实例的时候,可能websocket还没实例化,所以要做成异步的形式来获取实例。

一、封装。先创建 socket.ts 文件

import EventEmitter from 'events'; // 这里用到了 events 包
const ee = new EventEmitter();
class Ws {
  private wsUrl: string = '';
  private socket: WebSocket | undefined; // socket实例
  private lockReconnect: boolean = false; // 重连锁
  private timeout: NodeJS.Timeout | undefined;

  // 初始化socket,一般在应用启动时初始化一次就好了,或者需要更换wsUrl
  public init(wsUrl: string) {
    this.wsUrl = wsUrl;
    this.createWebSocket();
  }

  // 获取socket实例
  public getInstance(): Promise<WebSocket> {
    return new Promise((resolve, reject) => {
      if (this.socket) {
        resolve(this.socket);
      } else {
        ee.on('socket', (state: string) => {
          if (state === 'success') {
            resolve(this.socket);
          } else {
            reject();
          }
        });
      }
    });
  }

  // 创建socket
  private createWebSocket() {
    try {
      console.log('websocket 开始链接');
      const socket = new WebSocket(this.wsUrl);
      socket.addEventListener('close', () => {
        console.log('websocket 链接关闭');
        this.socket = undefined;
        this.reconnect();
      });
      socket.addEventListener('error', () => {
        console.log('websocket 发生异常了');
        this.socket = undefined;
        this.reconnect();
      });
      socket.addEventListener('open', () => {
        // 可在此进行心跳检测
        // this.heartCheck.start();
        console.log('websocket open');
        this.socket = socket;
        ee.emit('socket', 'success');
      });
      socket.addEventListener('message', (event) => {
        console.log('websocket 接收到消息', event);
      });
    } catch (e) {
      console.log('socket catch error', e);
      this.reconnect();
    }
  }

  // 重连
  private reconnect() {
    if (this.lockReconnect) {
      return;
    }
    console.log('websocket 正在重新连接');
    this.lockReconnect = true;
    //没连接上会一直重连,设置延迟避免请求过多
    this.timeout && clearTimeout(this.timeout);
    this.timeout = setTimeout(() => {
      this.createWebSocket();
      this.lockReconnect = false;
    }, 5000);
  }
}

export default new Ws();

二、引入并使用

import socket from '@/utils/ws';

socket
  .getInstance()
  .then((ws) => {
      // 这里的 ws 就是实例化后的 websocket,可以直接使用 websocket 原生 api
    console.log('getInstance ws', ws);
    ws.addEventListener('message', (event) => {
        console.log('ws 接收到消息', event);
      });
  })
  .catch(() => {});
0 条评论

暂无评论