DEV Community

Cover image for Using Web Worker API In Your Reactjs Project To Enhance Performance
Andika
Andika

Posted on • Originally published at Medium

Using Web Worker API In Your Reactjs Project To Enhance Performance

What is a web worker? 

This is a question beginners learning frontend often ask. Sometimes, they can't wrap their head around reasons for using the web worker API and when it should be used.

Web Workers in simple terms, are a means to run a set of instructions in the background. Why background? Javascript was created in 1995 to run small bits of tasks on the web browser. Javascript is designed to run non-concurrently (i.e. run one task at a time) on a single main thread. Web Worker makes it possible to create another thread called the worker thread to run tasks, without interfering with the user interface.

Developers use Web Worker API to ease the burden of tasks on the main thread. Running memory-intensive tasks like implementing autosave functionality (for writing web apps, e.g. Google Docs), can affect user interactions and cause lagging. Web worker makes it possible to assign those tasks to another thread.

diagram to show how web workers work Left: Without web worker, Right: With web worker

Using web worker in cases like the one mentioned above helps to;

  • improve the responsiveness and avoid freezing of the web app,
  • improve the overall performance of the web app, and
  • better make use of the CPU resources by utilizing multiple threads

Real-World Use Cases of Web Workers

Web worker is used in web applications that have the following features:

  1. Image processing: For web apps with features like image resizing, filtering, manipulation and facial recognition. Web workers can be used for complex canvas manipulations or image rendering in the background.
  2. Video encoding and decoding: Developers use web workers in streaming apps to process video files for playback or manipulation without freezing the user interface.
  3. Real-time applications: Real-time applications that use socket.io for fetching data. Web apps like messaging platforms, and crypto dashboard shows the latest price of cryptocurrencies in a chart.
  4. Background Tasks: Web workers can handle tasks that don't require immediate visual updates on the page. Examples include syntax highlighting in online code editors. It is also used to fetch large amounts of backend API data.

Web Worker API

There are two types of web workers:

Shared Worker

The shared worker is accessible to multiple pages and scripts. The shared worker is spawned by calling the SharedWorker() constructor.

const worker = new SharedWorker('worker.js')
Enter fullscreen mode Exit fullscreen mode

Dedicated Worker

A dedicated worker is only accessible to the script that called it. This way, only the page that called it can communicate with it.
A dedicated worker is created by calling the Worker() constructor. The constructor takes the script's path to run in the worker thread as a parameter.

const worker = new Worker('worker.js')
Enter fullscreen mode Exit fullscreen mode

Communication with a dedicated worker

To send a message to and from a dedicated worker, postMessage() is used. The onmessage method is for listening to messages.

The postMessage() takes in the data or message to be sent as a parameter. The data can be any javascript object, with exemptions like functions and DOM nodes. This is because data is copied between the main page and the worker, not shared. The page and worker do not share the same instance, i.e. duplicate result is created on each side.

Terminating web worker

To terminate a running web worker from the main thread, the terminate() method is used.

Web Worker Limitations

While web worker API is a powerful tool to improve performance, there are a few limitations to keep in mind when working with them.

  • Web workers do not have access to all window objects, e.g. window.location,
  • It can not directly manipulate the DOM. 🙅‍♂️ No document.addEventListener()

Checkout list of functions and classes available to web workers: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers

Implementing web worker in Reactjs applications

To better understand the concept of how web workers work, let's consider an example in a Reactjs app.

To imitate a memory-intensive task, we will create a function that returns the factorial of a random number from 0–100.

//Memory-intensive calculation

export default function calcFactorial() {
const randomNum = Math.floor(Math.random() * 100);
let factorial = 1;
if (randomNum === 0) {
return 1;
}
for (let i = 1; i <= randomNum; i++) {
factorial *= i;
}
return factorial;
}
Enter fullscreen mode Exit fullscreen mode

To create a web worker, we need a js file (e.g. worker.js). In this file, we listen to messages from app.js using the onmessage method. The message.data from the parameter is a boolean that determines if the calculation should start or stop. If message.data is true, we run calcFactorial() and send the returned value to app.js every 2 seconds.

//worker.js

import calcFactorial from "../utils/randomNum";
onmessage = function (message) {
const init = message.data;
if (init) {
setInterval(() => {
const randomFactorial = calcFactorial();
postMessage(randomFactorial);
}, 2000);
} else {
return;
}
};
Enter fullscreen mode Exit fullscreen mode

In app.js, we initialize a dedicated worker and communicate with the worker.js file using postMessage() and onmessage methods.

import { useState, useEffect } from "react";

function App() {

//initialize web worker
const worker = new Worker(new URL("./worker/worker.js", import.meta.url), {
type: "module",
});

const [initWorker, setInitWorker] = useState(false);
const [randomFactorial, setRandomFactorial] = useState(0);

useEffect(() => {

//communicates with the worker file
if (initWorker) {
worker.postMessage(true);
}
worker.onmessage = function (e) {
setRandomFactorial(e.data);
};

return (()=>{
worker.terminate()
})
}, [initWorker, randomFactorial]);

const handleClick = () => {
setInitWorker(!initWorker);
};

return (
<div>
<h1>Web worker example</h1>
<div className='randomNumBox'>
<h2>Random Factorial: {randomFactorial}</h2>
<button onClick={handleClick}>{initWorker ? "Stop" : "Start"}</button>
</div>
</div>
);
}
export default App;
Enter fullscreen mode Exit fullscreen mode

Result

result

https://github.com/psalmuelle/andika-tutorial/tree/worker

Conclusion

In this article, we explored the web worker API and how it is being used to improve web performance. Here are additional resources to know more about web worker API:

Top comments (0)