基于vue3.0和element-plus的组件库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

5.0 KiB

WebSocket

WebSocket connection management with message handler registration.


Overview

The WebSocket module provides connection management, message queuing, automatic reconnection, and handler registration for different message types.


Architecture

WebSocket Module
├── websocket (WebSocket instance)
├── msgHandlersMap (type -> handlers mapping)
├── messageQueue (pending messages)
├── openWebSocket() - connect with auto-reconnect
├── closeWebSocket() - graceful disconnect
├── sendSocketMsg() - send with queue fallback
└── registerHandler() - subscribe to message types

Connection Management

File: /home/hechang27/Documents/sprt/noob-components/plugs/websocket.ts

State

let websocket: WebSocket;
const msgHandlersMap = {};
let lastUrl;
let closeFlag = false;
const messageQueue: any[] = [];
Variable Type Description
websocket WebSocket Current WebSocket connection
msgHandlersMap object Maps message type to handler objects
lastUrl string Last connected URL (for reconnect check)
closeFlag boolean Manual close flag (vs auto-reconnect)
messageQueue array Queued messages when disconnected

Core Functions

openWebSocket

Connects to WebSocket URL with auto-reconnect on unexpected close.

export const openWebSocket = (url) => {
  if (websocket && websocket.readyState === WebSocket.OPEN) {
    if (lastUrl == url) {
      return; // Already connected to same URL
    }
    closeWebSocket();
  }
  websocket = new WebSocket(url);
  lastUrl = url;

  websocket.onopen = () => {
    console.log("websocket已连接");
    closeFlag = true;
    // Flush queued messages
    while (messageQueue.length > 0) {
      const msg = messageQueue.shift();
      websocket.send(JSON.stringify(msg));
    }
  };

  websocket.onmessage = (msg) => {
    const event = JSON.parse(msg.data);
    const handlers = msgHandlersMap[event.type];
    if (!handlers) {
      return;
    }
    Object.values(handlers).forEach((handler: any) => {
      handler(event.data);
    });
  };

  websocket.onclose = () => {
    console.log("websocket已断开");
    if (closeFlag) {
      // Auto-reconnect after 2 seconds
      setTimeout(() => {
        openWebSocket(url);
      }, 2000);
    }
  };
};

closeWebSocket

Closes connection and prevents auto-reconnect.

export const closeWebSocket = () => {
  closeFlag = false;
  websocket?.close();
};

sendSocketMsg

Sends message, queues if not connected.

export const sendSocketMsg = (msg) => {
  if (websocket && websocket.readyState === WebSocket.OPEN) {
    websocket.send(JSON.stringify(msg));
  } else {
    messageQueue.push(msg);
  }
};

registerHandler

Registers handler for a message type.

export const registerHandler = (type, key, handler) => {
  const handlers = msgHandlersMap[type] || {};
  handlers[key] = handler;
  msgHandlersMap[type] = handlers;
};

Message Flow

1. openWebSocket(url)
       |
       v
   WebSocket.OPEN
       |
       v
   onopen handler
       |
       v
   Flush messageQueue
       |
       v
2. Server sends message
       |
       v
   onmessage handler
       |
       v
   Parse JSON { type, data }
       |
       v
   Lookup msgHandlersMap[type]
       |
       v
   Call all handlers with data

Handler Registration Pattern

// Register a handler
const myHandler = (data) => {
  console.log('Received:', data);
};

registerHandler('refresh', 'myComponent', myHandler);

// Later, unregister by setting to null or removing key
delete msgHandlersMap['refresh']['myComponent'];

Usage Example

import {
  openWebSocket,
  closeWebSocket,
  sendSocketMsg,
  registerHandler,
} from './websocket';

// Connect
openWebSocket('wss://api.example.com/ws');

// Subscribe to messages
registerHandler('refresh', 'dashboard', (data) => {
  dashboard.update(data);
});

registerHandler('notification', 'toast', (data) => {
  showToast(data.message);
});

// Send message
sendSocketMsg({ type: 'subscribe', channels: ['refresh', 'notification'] });

// Cleanup on component unmount
onUnmounted(() => {
  delete msgHandlersMap['refresh']['dashboard'];
  delete msgHandlersMap['notification']['toast'];
});

Auto-Reconnect Behavior

  • Unexpected disconnect: closeFlag = true causes auto-reconnect after 2 seconds
  • Manual close: closeWebSocket() sets closeFlag = false to prevent reconnect
  • Same URL check: Connecting to same URL while already connected is a no-op

Anti-Patterns

  1. Do not register handlers with duplicate keys - Each key should be unique per type
  2. Do not forget to unregister handlers - This causes memory leaks and stale handlers
  3. Do not assume messages are always JSON - Always handle parse errors
  4. Do not send messages before connection - Messages are queued but check readyState if critical

Language: English