Create a Websocket client in Javascript using a web worker
This is a short tutorial on how to create a JavaScript WebSocket client that runs in a Web Worker. The finished files can be downloaded at: github Introduction: The goal is to exchange data between a WebSocket server and the web client in real time. I decided to use a Web Worker to outsource the handling of the WebSocket data flow from the main thread, to reducing the communication load. I also implemented a reconnection logic, since the connection could not be establish or was closed unexpectedly We will create two files: index.html: contains the load of the web worker and processing datas from the WebSocket connection websocketHandler.worker.js: The web worker file, handling of the WebSocket connection and datas Short infos to Web workers A web worker... runs in a separate thread, independent from your web browser's main thread cannot access or manipulate the DOM communicates with the main thread using messages via "postMessage" runs in a separate .js file Creating the Websocket client Let's start by creating a JavaScript file named websocketHandler.worker.js At the top, we’ll add some variables that we’ll use later let socket = null; // contains the socket object let shouldReconnect = true; // a flag when we want to auto reconnect let reconnectTimeout = null; // contains the reconnect timer let wsServerUrl = '' // the URL to our WebSocket server Next we add a "onmessage" event function for handling incoming messages to the web worker. onmessage = function (e) { const data = e.data; handlingWebSocket(data); }; This will be triggered when a message sent to the web worker. The format for this messages will be: wsWorker.postMessage({ type: '', payload: '' }); Create also a function handlingWebSocket(data); for processing the WebSocket interface function handlingWebSocket(data) {} Now in this function, we create a handling of the different incoming messages-types (connect, send, disconnect). For this create a switch-case for the different message-types: switch (data.type) { case 'connect': // Logic to open the connection to the websocket server break; case 'send': // sending a message to the web socket server break; case 'disconnect': // disconnet and do some clean up break; } } Let's fill the different cases. Case: connect - Connect to the Websocket server. When message of type "connect" wsWorker.postMessage({ type: 'connect', wsServerUrl: 'ws://192.168.100.150:4040' }); is coming to the web worker, we check if still a connection is open, clean the socket object for safty and then call a seperated connectToWebsocket function. case 'connect': // save URL in local variable wsServerUrl = data.wsServerUrl // set auto reconnect, so when a connection could not be established it will try to reconnect again shouldReconnect = true // be sure that there is not still a WebSocket server object if (socket && socket.readyState !== WebSocket.CLOSED && socket.readyState !== WebSocket.CLOSING) { return; } // to be save the object is empty socket = null; // call the function to open the connection connectToWebSocket(wsServerUrl); break; Then we create and fill the connectToWebsocket function function connectToWebSocket(wsServerUrl) { console.dir("Start connection to WebsocketServer..."); // open the connection to the WebSocket server socket = new WebSocket(wsServerUrl); // event which triggered when the connection has been established socket.onopen = () => { // clear the timeout when the connection was established clearTimeout(reconnectTimeout); // send message to parent function that the connection was established postMessage({ type: 'connected' }); }; // event when a message comes from the WebSocket server socket.onmessage = (event) => { try { const msgContent = JSON.parse(event.data); postMessage({ type: 'data', payload: msgContent }); } catch (err) { postMessage({ type: 'error', payload: "Error at parsing message datas" }); } }; // event will be triggered when an error with the WebSocket interfaces raised socket.onerror = (err) => { postMessage({ type: 'error', payload: err.message }); }; // event which triggered when the connection to the WebSocket server will be closed socket.onclose = () => { postMessage({ type: 'closed' }); // clean up before try to reconnect disposeWebSocket() // check if reconnection should be running if (shouldReconnect) { postMessage({ type: 'reconnect' }); // set a timeout every 5sec for trying to reconnect reconnectTimeout = setTimeout( () => connectToWebSocket(wsServerUrl), 5000);

This is a short tutorial on how to create a JavaScript WebSocket client that runs in a Web Worker.
The finished files can be downloaded at: github
Introduction:
The goal is to exchange data between a WebSocket server and the web client in real time. I decided to use a Web Worker to outsource the handling of the WebSocket data flow from the main thread,
to reducing the communication load.
I also implemented a reconnection logic, since the connection could not be establish or was closed unexpectedly
We will create two files:
- index.html: contains the load of the web worker and processing datas from the WebSocket connection
- websocketHandler.worker.js: The web worker file, handling of the WebSocket connection and datas
Short infos to Web workers
A web worker...
- runs in a separate thread, independent from your web browser's main thread
- cannot access or manipulate the DOM
- communicates with the main thread using messages via "postMessage"
- runs in a separate .js file
Creating the Websocket client
- Let's start by creating a JavaScript file named websocketHandler.worker.js
- At the top, we’ll add some variables that we’ll use later
let socket = null; // contains the socket object
let shouldReconnect = true; // a flag when we want to auto reconnect
let reconnectTimeout = null; // contains the reconnect timer
let wsServerUrl = '' // the URL to our WebSocket server
- Next we add a "onmessage" event function for handling incoming messages to the web worker.
onmessage = function (e) {
const data = e.data;
handlingWebSocket(data);
};
This will be triggered when a message sent to the web worker. The format for this messages will be: wsWorker.postMessage({ type: '
- Create also a function handlingWebSocket(data); for processing the WebSocket interface
function handlingWebSocket(data) {}
- Now in this function, we create a handling of the different incoming messages-types (connect, send, disconnect). For this create a switch-case for the different message-types:
switch (data.type) {
case 'connect':
// Logic to open the connection to the websocket server
break;
case 'send':
// sending a message to the web socket server
break;
case 'disconnect':
// disconnet and do some clean up
break;
}
}
Let's fill the different cases.
- Case: connect - Connect to the Websocket server.
When message of type "connect" wsWorker.postMessage({ type: 'connect', wsServerUrl: 'ws://192.168.100.150:4040' });
is coming to the web worker,
we check if still a connection is open, clean the socket object for safty and then call a seperated connectToWebsocket function.
case 'connect':
// save URL in local variable
wsServerUrl = data.wsServerUrl
// set auto reconnect, so when a connection could not be established it will try to reconnect again
shouldReconnect = true
// be sure that there is not still a WebSocket server object
if (socket && socket.readyState !== WebSocket.CLOSED && socket.readyState !== WebSocket.CLOSING) {
return;
}
// to be save the object is empty
socket = null;
// call the function to open the connection
connectToWebSocket(wsServerUrl);
break;
Then we create and fill the connectToWebsocket function
function connectToWebSocket(wsServerUrl) {
console.dir("Start connection to WebsocketServer...");
// open the connection to the WebSocket server
socket = new WebSocket(wsServerUrl);
// event which triggered when the connection has been established
socket.onopen = () => {
// clear the timeout when the connection was established
clearTimeout(reconnectTimeout);
// send message to parent function that the connection was established
postMessage({ type: 'connected' });
};
// event when a message comes from the WebSocket server
socket.onmessage = (event) => {
try {
const msgContent = JSON.parse(event.data);
postMessage({ type: 'data', payload: msgContent });
} catch (err) {
postMessage({ type: 'error', payload: "Error at parsing message datas" });
}
};
// event will be triggered when an error with the WebSocket interfaces raised
socket.onerror = (err) => {
postMessage({ type: 'error', payload: err.message });
};
// event which triggered when the connection to the WebSocket server will be closed
socket.onclose = () => {
postMessage({ type: 'closed' });
// clean up before try to reconnect
disposeWebSocket()
// check if reconnection should be running
if (shouldReconnect) {
postMessage({ type: 'reconnect' });
// set a timeout every 5sec for trying to reconnect
reconnectTimeout = setTimeout(
() => connectToWebSocket(wsServerUrl),
5000);
}
};
}
- We also have to create a dispose function "disposeWebSocket()" to do a clean up
function disposeWebSocket() {
clearTimeout(reconnectTimeout);
if (socket) {
socket.onopen = null;
socket.onmessage = null;
socket.onerror = null;
socket.onclose = null;
socket = null;
}
}
- Case: send - Next we fill the case for sending datas to the WebSocket sever. We check if the connection is still open before we send datas.
case 'send':
// check if the connection still open before sending datas
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify(data.payload));
}
break;
- Case: disconnect - Finally we create the case for disconnecting from the WebSocket server. We call this when we leave the page or the communication should be ending.
case 'disconnect':
// prevent auto reconnect when the connection was active closed
shouldReconnect = false
if (socket) {
// we call the close method and pass a status code.
// code 1000 means normal closure
socket.close(1000, "Client closing connection");
console.dir("Sent CLOSE-connection request to server");
}
// call the dispose function to clean up
disposeWebSocket();
// set the command to end up the web worker semselfe
self.close();
break;
As next we'll create the logic for using our WebSocket web worker
- First create the index.html file with a default base structure like this:
WebSocket Worker Demo
WebSocket Worker
Connecting...
- Inside the "srcipt" tag we start with create the web worker object
const wsWorker = new Worker('websocketHandler.worker.js');
- We use the object and send a postMessage of type: "connect" to call the web worker to connect to the WebSocket server like this:
wsWorker.postMessage({ type: 'connect', wsServerUrl: 'ws://192.168.100.150:4040' });
- Then we add a handling for messages from the web worker
wsWorker.onmessage = (event) => {
const { type, payload } = event.data;
const statusEl = document.getElementById('status');
if (type === 'connected') {
statusEl.textContent = "#### CONNECTION to WebSocketServer ESTABLISHED ####";
} else if (type === 'data') {
console.dir('Data incomming: ' + JSON.stringify(payload));
} else if (type === 'error') {
statusEl.textContent = "Error: " + JSON.stringify(payload);
} else if (type === 'closed') {
statusEl.textContent = "WebSocket is closed";
}else if (type === 'reconnect'){
statusEl.textContent = "Connection to WebSocketServer closed - Try to reconnect...";
}
};
- We also add a function to test the sending of datas to the websocket server
function sendDatasToWss(){
console.log("Sending datas to WSS");
wsWorker.postMessage({ type: 'send', msgContent: 'SomeDatas you need in the WSS' });
}
- Do a clean up when the page will be leave
window.addEventListener('beforeunload', () => {
wsWorker.postMessage({ type: 'disconnect' });
// Give the worker time to clean up before terminate the web worker
setTimeout(
() => wsWorker.terminate(),
10);
});
When we now open the index.html file and the WebSocket connection should be established.
We see what's happening in the
on the page.