Building a WebSocket Manager for Real‑Time Message Push in JavaScript
This article demonstrates how to create a reusable WebSocket manager in JavaScript that handles connection creation, automatic heartbeat, message sending, reconnection attempts, and graceful closure, providing a complete front‑end solution for real‑time communication without relying on polling.
Requirement Analysis
The module should be encapsulated in a class and provide the following capabilities:
Create and close a WebSocket object.
Enable a heartbeat mechanism to keep the connection alive.
Push incoming messages to business‑logic callbacks.
Implement a reconnection strategy with a maximum number of attempts.
Implementation
Create WebSocket Class
File WebSocketManager.js defines the WebSocketManager class and initializes essential properties.
export default class WebSocketManager {
constructor(url = null, userId = null, receiveMessageCallback = null) {
this.socket = null; // WebSocket object
this.pingTimeout = null; // heartbeat timer
this.reconnectTimeout = 5000; // reconnection interval (ms)
this.maxReconnectAttempts = 10; // max reconnection attempts
this.reconnectAttempts = 0; // current attempt count
this.id = userId; // user identifier
this.url = url; // WebSocket server URL
this.receiveMessageCallback = receiveMessageCallback; // callback for received messages
}
}Initialize WebSocket Object
The start method checks that both URL and user ID are provided before establishing the connection.
export default class WebSocketManager {
constructor() {
// ... omitted
}
/**
* Initialize
*/
async start() {
if (this.url && this.id) {
// connect WebSocket
this.connectWebSocket();
} else {
console.error('WebSocketManager errors: please provide connection URL and user ID');
}
}
}Create WebSocket Connection
The connectWebSocket method builds a unique identifier from the user ID and a random value, creates the WebSocket instance, and registers event listeners for open, message, close, and error events.
export default class WebSocketManager {
constructor() {
// ... omitted
}
/**
* Create WebSocket connection
*/
connectWebSocket() {
// generate unique ID (server‑side requirement)
let id = `${this.id}-${Math.random()}`;
// create WebSocket object
this.socket = new WebSocket(this.url, id);
// handle open event – start heartbeat
this.socket.addEventListener('open', event => {
this.startHeartbeat();
});
// handle incoming messages
this.socket.addEventListener('message', event => {
this.receiveMessage(event);
});
// handle close event – attempt reconnection
this.socket.addEventListener('close', event => {
clearTimeout(this.pingTimeout);
clearTimeout(this.reconnectTimeout);
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
this.reconnectTimeout = setTimeout(() => {
this.connectWebSocket();
}, this.reconnectTimeout);
} else {
// reset attempts after reaching the limit
this.reconnectAttempts = 0;
console.error('WebSocketManager errors: Max reconnect attempts reached. Unable to reconnect.');
}
});
// handle error event
this.socket.addEventListener('error', event => {
console.error('WebSocketManager error:', event);
});
}
}Heartbeat Mechanism
A periodic ping message is sent every 10 seconds to keep the connection alive.
export default class WebSocketManager {
constructor() {
// ... omitted
}
/**
* Start heartbeat
*/
startHeartbeat() {
this.pingTimeout = setInterval(() => {
// send heartbeat message
this.sendMessage('ping');
}, 10000); // every 10 seconds
}
/**
* Send a message
* @param {String} message Message content
*/
sendMessage(message) {
if (this.socket.readyState === WebSocket.OPEN) {
this.socket.send(message);
} else {
console.error('WebSocketManager error: WebSocket connection is not open. Unable to send message.');
}
}
}Receive Message
The receiveMessage method logs the incoming data and forwards it to the user‑provided callback.
export default class WebSocketManager {
constructor() {
// ... omitted
}
/**
* Handle received message
*/
receiveMessage(event) {
// custom business logic here
console.log('receiveMessage:', event.data);
this.receiveMessageCallback && receiveMessageCallback(event.data);
}
}Close Connection
The closeWebSocket method terminates the socket and clears all timers.
export default class WebSocketManager {
constructor() {
// ... omitted
}
/**
* Close the connection
*/
closeWebSocket() {
this.socket.close();
// clear timers and reset attempts
clearTimeout(this.pingTimeout);
clearTimeout(this.reconnectTimeout);
this.reconnectAttempts = 0;
}
}Usage Example
Import the manager, provide a message‑handling callback, instantiate it with the server URL and user ID, and start the connection.
/**
* Message callback
*/
const receiveMessage = (res) => {
console.log('Received message callback:', res);
};
const socketManager = new WebSocketManager('ws://example.com/socket', 'userid292992', receiveMessage);
socketManager.start();Conclusion
The code above offers a straightforward WebSocket implementation for front‑end projects. Developers can adapt and extend it according to specific business requirements. For the full source, refer to the linked GitHub repository.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.