websocket的封装

267 阅读1分钟

ws.js

const eventMap = new Map();
const serviceMap = new Map();
const event = {
  onopen: [],
  onmessage: [],
  onclose: [],
  onerror: []
};

export class SocketService {
  socketInstance = null; //
  initOpt = null; // 初始化socket的参数
  timer = null; // 断开重连定时器
  reconnecTime = 1000 * 5; // 断开重连时间
  lockReconnect = false; // 是否已经执行重连
  constructor({ url, params, ...rest }) {
    this.initOpt = { url, params, ...rest };
    try {
      this.socketInstance = new WebSocket(url);
      SocketService.collectEvent(this.initOpt, this, true);
      Object.keys(event).forEach((key) => {
        const funList = eventMap.has(url) && eventMap.get(url)[key];
        this.socketInstance[key] = (e) => {
          if (e.type == 'message') {
            // 统一处理消息数据
            e = e.data;
          } else if (['onclose', 'onerror'].includes(key)) {
            // 关闭或者报错 进行重新连接
            console.log(`失败类型:${e.type}`, e);
            SocketService.reconnect(this);
          }
          if (Array.isArray(funList)) {
            funList.forEach((fun) => {
              if (typeof fun == 'function') fun(e, key);
            });
          }
        };
      });
    } catch (err) {
      console.log('创建socket失败constructor', err);
      SocketService.reconnect(this, '初始化');
    }
  }
  send(params) {
    if (params) params = JSON.stringify(params);
    this.initOpt.params = params;
    this.socketInstance.send(params);
    return this;
  }
  close() {
    if (this.socketInstance) {
      this.socketInstance.close();
      this.socketInstance = null;
      this.lockReconnect = true; // 防止因为主动关闭 而导致的重新连接
      this.timer && clearTimeout(this.timer);
      serviceMap.delete(this.initOpt.url); // 删除服务实例
      eventMap.delete(this.initOpt.url); // 删除事件
    }
    return this;
  }
  static closeAll() {
    serviceMap.forEach((i) => {
      if (i) i.close();
    });
    serviceMap.clear(); // 清空服务
    eventMap.clear(); // 清空事件
  }
  static collectEvent({ url = '', params, ...rest }, serviceInstance, restFlag) {
    // 收集事件
    if (!eventMap.has(url) || restFlag) eventMap.set(url, JSON.parse(JSON.stringify(event)));
    if (params && restFlag) {
      // 重新连接 或者 初始化实例 连接成功发送数据
      eventMap.get(url)['onopen'].push(() => {
        serviceInstance.send(params);
      });
    }
    Object.keys(rest).forEach((key) => {
      const lowKey = (key || '').toLowerCase();
      if (typeof rest[key] == 'function' && event[lowKey]) {
        // 判断是函数 并且是列表里面的函数
        eventMap.get(url)[lowKey].push(rest[key]);
      }
    });
    if (params && serviceInstance.socketInstance.readyState == 1) {
      // 已经初始化 并且有params 发送一次数据
      serviceInstance.send(params);
    }
  }
  static reconnect(serviceSelf) {
    if (serviceSelf.lockReconnect) {
      // 是否已经执行重连
      return;
    }
    serviceSelf.lockReconnect = true;
    //没连接上会一直重连,设置延迟避免请求过多
    serviceSelf.timer && clearTimeout(serviceSelf.timer);
    serviceSelf.timer = setTimeout(() => {
      const socketService = new SocketService(serviceSelf.initOpt);
      serviceMap.set(serviceSelf.initOpt.url, socketService);
      serviceSelf.lockReconnect = false;
    }, 5000);
  }
}

export const socketRequest = (opt) => {
  if (typeof opt.params == 'object' && Object.keys(opt.params).length == 0) opt.params = null;
  let service = null;
  if (serviceMap.has(opt.url)) {
    service = serviceMap.get(opt.url);
    SocketService.collectEvent(opt, service);
  } else {
    service = new SocketService(opt);
    serviceMap.set(opt.url, service);
  }
  return service;
};

配置api

/**
 * @description: 消息通知
 */
export function SApiMessageNotice(opt = { params: '' }) {
  const url = `ws${wsIp}/websocket/${store.state && store.state.userInfo && store.state.userInfo.account}?authToken=${
    store.state.authorization
  }`; // 消息通知
  return socketRequest({
    url,
    ...opt
  });

调用api

      SApiMessageNotice({
        params: {},
        onMessage: (res) => {
          if (typeof res !== 'string') res = JSON.stringify(res);
          notification.open({
            message: '消息通知',
            // duration: 3,
            description: res,
            onClick: () => {
              console.log('Notification Clicked!');
            }
          });
        }
      });