MultiThreading In JS using Web Workers

Anas Mustafa - Aug 14 - - Dev Community

Web Worker: a way to run scripts in the background in different thread than the current main(Window)thread.

  1. Web workers vs asynchronous using event_loop
  2. Introduction to Web Workers
  3. how to create a web worker
  4. For example with a web worker
  5. limitation of Web Workers
  6. asynchronous operation in Web Workers

1. Web Workers vs Asynchronous Operations Using Event Loop

JavaScript typically handles asynchronous operations by placing tasks into corresponding queues (macro-task queue, micro-task queue), with the event loop continuously checking these queues and pushing tasks into the call stack when they're ready to be executed. This approach ensures non-blocking execution but still runs everything on a single thread.

Web Workers, on the other hand, allow scripts to run in a completely separate thread with its own call stack, asynchronous queues, and event loop. This separation prevents the main thread from being blocked by heavy computations or long-running tasks, as the worker operates independently.

2. Introduction to Web Workers

Web workers execute scripts in a different context than the main window context, enabling parallelism in web applications. The Web Worker API provides several types of workers:

  • Dedicated Workers: Utilized by a single script, these are ideal for offloading tasks from the main thread.
  • Shared Workers: Accessible by multiple scripts running in different contexts (e.g., different windows or iframes).
  • Service Workers: Operate as a proxy server between web applications, the browser, and the network, providing functionalities like offline support and caching.

This article focuses on dedicated workers, which are the most straightforward to implement and commonly used.

3. How to Create a Web Worker

To create a web worker, you can use the following key methods:

  • new Worker(): The constructor to create a new worker.
  • postMessage(): Sends messages from the main thread to the worker or vice versa.
  • onmessage: A callback function set to handle messages received by the worker.
  • terminate(): Stops the worker immediately.

4. Simple Example

Let’s create a worker to fetch data from an API, specifically dog images from the Dog CEO API.

4.1 Worker Code

Here’s the implementation of the worker script. Notice that inside the worker, self is used to refer to the global context:

if (window.Worker) {
    const worker = new Worker("/src/worker.js");
        worker.postMessage({ 
            operation: "get_dog_imgs",
            url: "https://dog.ceo/api/breeds/image/random", 
            count: 5   //number of photos
        });
        worker.onmessage = (e) => {
        console.log(e.data);
        if (e && e.data) {
            setdata((old) => [...old, e.data]); // update react state
            showCallStack(); // function to show the callstack 
        }
    };
    worker.onerror = (e) => {
        console.log(e);
    };
}
Enter fullscreen mode Exit fullscreen mode

In this code, the worker listens for messages (onmessage) and fetches data from the given URL multiple times as specified by the count.

Here’s what the call stack looks like inside the worker:

web worker call stack

4.2 Client Code

The main thread uses the worker like this:

self.onmessage = (event) => {
    const data = event.data;
    if (data && data.url && data.count) {
        fetchFromUrls(data.url, data.count);
    }
}
// fetch single data 
const fetchdata = async (url) => {
    const res = await self.fetch(url);
    return await res.json();
};

const fetchFromUrls = async (url, count) => {
    showCallStack(); // showing the callstack of the worker 
    for (const i of new Array(count).fill(0)) {
        let data = await fetchdata(url);
        if (data && data.message) {
            self.postMessage({ type: "img", data: data.message });
        }
    }
};
Enter fullscreen mode Exit fullscreen mode

This code demonstrates how to send a message to the worker and receive the fetched data in the main thread.

window context call stack

for full code go to code

gif showing the run code

5. Limitations of Web Workers

While web workers run in a separate thread from the main window thread, they come with certain limitations:

  • No Access to DOM: Workers cannot directly manipulate the DOM. Communication with the main thread is necessary to update the UI.
  • Resource Consumption: Overusing web workers can lead to high memory usage, as each worker requires additional resources to operate independently.
. . .
Terabox Video Player