DEV Community

Cover image for Create a Websocket client in Javascript using a web worker
JerDox
JerDox

Posted on

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 
Enter fullscreen mode Exit fullscreen mode
  • Next we add a "onmessage" event function for handling incoming messages to the web worker.
onmessage = function (e) { const data = e.data; handlingWebSocket(data); }; 
Enter fullscreen mode Exit fullscreen mode

This will be triggered when a message sent to the web worker. The format for this messages will be: wsWorker.postMessage({ type: '<will be connect, send or disconnect>', payload: '<datas of the message>' });

  • Create also a function handlingWebSocket(data); for processing the WebSocket interface
function handlingWebSocket(data) {} 
Enter fullscreen mode Exit fullscreen mode
  • 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; } } 
Enter fullscreen mode Exit fullscreen mode

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; 
Enter fullscreen mode Exit fullscreen mode

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); } }; } 
Enter fullscreen mode Exit fullscreen mode
  • 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; } } 
Enter fullscreen mode Exit fullscreen mode
  • 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; 
Enter fullscreen mode Exit fullscreen mode
  • 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; 
Enter fullscreen mode Exit fullscreen mode

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:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>WebSocket Worker Demo</title> </head> <body> <h2>WebSocket Worker</h2> <div id="status">Connecting...</div> <!-- Button for sending datas to the websocket server --> <button onclick="sendDatasToWss()">send datas to WSS</button> <script> // here we palce the logig for the websocket interface </script> </body> </html> 
Enter fullscreen mode Exit fullscreen mode
  • Inside the "srcipt" tag we start with create the web worker object
const wsWorker = new Worker('websocketHandler.worker.js'); 
Enter fullscreen mode Exit fullscreen mode
  • 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' }); 
Enter fullscreen mode Exit fullscreen mode
  • 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..."; } }; 
Enter fullscreen mode Exit fullscreen mode
  • 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' }); } 
Enter fullscreen mode Exit fullscreen mode
  • 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); }); 
Enter fullscreen mode Exit fullscreen mode

When we now open the index.html file and the WebSocket connection should be established.

We see what's happening in the <div id="status">Connecting...</div> on the page.

Top comments (0)