How to Reconnect WebSockets Reliably
WebSockets are a powerful tool for real-time communication between a client and a server. However, handling connection interruptions and ensuring reliability can be challenging. This guide demonstrates how to implement a robust WebSocket encapsulation with automatic reconnection, event listeners, and customizable parameters.
Why Encapsulate WebSocket Logic?
By encapsulating WebSocket logic, you:
- Simplify implementation across your app.
- Handle reconnection automatically without duplicating code.
- Improve maintainability and scalability.
Key Features of the WebSocket Encapsulation
- Automatic Reconnection
- Event Listeners
- Customizable Parameters
- Error Handling
Implementation: WebSocketReconnect Class
js
class WebSocketReconnect {
constructor(
url,
maxReconnectAttempts = 3,
reconnectInterval = 20000,
maxReconnectTime = 180000
) {
this.url = url;
this.maxReconnectAttempts = maxReconnectAttempts;
this.reconnectInterval = reconnectInterval;
this.maxReconnectTime = maxReconnectTime;
this.reconnectCount = 0;
this.reconnectTimeout = null;
this.startTime = null;
this.socket = null;
this.listenerEvents = {};
if (this.checkWssUrl()) {
this.connect();
}
}
checkWssUrl(url = this.url) {
if (/wss:\/\/.*/.test(url) || /ws:\/\/.*/.test(url)) {
return true;
} else {
console.error('Invalid WebSocket URL');
return false;
}
}
connect() {
console.log('Connecting...');
this.socket = new WebSocket(this.url);
this.socket.onopen = () => {
console.log('WebSocket Connection Opened');
this.triggerEvent('open');
this.clearReconnectTimeout();
this.reconnectCount = 0;
};
this.socket.onclose = event => {
console.log('WebSocket Connection Closed', event);
this.triggerEvent('close');
this.handleReconnect();
};
this.socket.onerror = error => {
console.error('WebSocket Error', error);
this.triggerEvent('error');
this.handleReconnect();
};
}
triggerEvent(type) {
const events = this.listenerEvents[type] || [];
events.forEach(callback => callback());
}
addEventListener(type, callback) {
if (!this.listenerEvents[type]) {
this.listenerEvents[type] = [];
}
this.listenerEvents[type].push(callback);
}
handleReconnect() {
if (
this.reconnectCount < this.maxReconnectAttempts &&
(!this.startTime || Date.now() - this.startTime < this.maxReconnectTime)
) {
this.reconnectCount++;
console.log(
`Reconnecting (${this.reconnectCount}/${this.maxReconnectAttempts})...`
);
this.reconnectTimeout = setTimeout(() => {
this.connect();
}, this.reconnectInterval);
if (!this.startTime) {
this.startTime = Date.now();
}
} else {
console.log('Max reconnection attempts reached or timeout exceeded.');
}
}
clearReconnectTimeout() {
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout);
this.reconnectTimeout = null;
}
}
close() {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.socket.close();
}
this.clearReconnectTimeout();
this.reconnectCount = 0;
this.startTime = null;
}
}Example Usage
js
import WebSocketReconnect from './WebSocketReconnect';
const ws = new WebSocketReconnect('ws://your-websocket-url');
ws.addEventListener('open', () => console.log('WebSocket opened'));
ws.addEventListener('close', () => console.log('WebSocket closed'));
ws.addEventListener('error', () => console.log('Error occurred'));
ws.close();