forked from mengyxu/noob-components
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
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 = truecauses auto-reconnect after 2 seconds - Manual close:
closeWebSocket()setscloseFlag = falseto prevent reconnect - Same URL check: Connecting to same URL while already connected is a no-op
Anti-Patterns
- Do not register handlers with duplicate keys - Each key should be unique per type
- Do not forget to unregister handlers - This causes memory leaks and stale handlers
- Do not assume messages are always JSON - Always handle parse errors
- Do not send messages before connection - Messages are queued but check
readyStateif critical
Language: English