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);

Apr 22, 2025 - 10:11
 0
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);
        }     
    };
}
  • 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

Connecting...
on the page.