基于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.

241 lines
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
```typescript
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.
```typescript
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.
```typescript
export const closeWebSocket = () => {
closeFlag = false;
websocket?.close();
};
```
### sendSocketMsg
Sends message, queues if not connected.
```typescript
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.
```typescript
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
```typescript
// 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
```typescript
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