Web Workers in JavaScript

Web Workers in JavaScript

This article explains Web Workers in JavaScript.

YouTube Video

javascript-web-worker.html
  1<!DOCTYPE html>
  2<html lang="en">
  3<head>
  4  <meta charset="UTF-8">
  5  <title>JavaScript &amp; HTML</title>
  6  <style>
  7    * {
  8        box-sizing: border-box;
  9    }
 10
 11    body {
 12        margin: 0;
 13        padding: 1em;
 14        padding-bottom: 10em;
 15        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 16        background-color: #f7f9fc;
 17        color: #333;
 18        line-height: 1.6;
 19    }
 20
 21    .container {
 22        max-width: 800px;
 23        margin: 0 auto;
 24        padding: 1em;
 25        background-color: #ffffff;
 26        border: 1px solid #ccc;
 27        border-radius: 10px;
 28        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 29    }
 30
 31    .container-flex {
 32        display: flex;
 33        flex-wrap: wrap;
 34        gap: 2em;
 35        max-width: 1000px;
 36        margin: 0 auto;
 37        padding: 1em;
 38        background-color: #ffffff;
 39        border: 1px solid #ccc;
 40        border-radius: 10px;
 41        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 42    }
 43
 44    .left-column, .right-column {
 45        flex: 1 1 200px;
 46        min-width: 200px;
 47    }
 48
 49    h1, h2 {
 50        font-size: 1.2rem;
 51        color: #007bff;
 52        margin-top: 0.5em;
 53        margin-bottom: 0.5em;
 54        border-left: 5px solid #007bff;
 55        padding-left: 0.6em;
 56        background-color: #e9f2ff;
 57    }
 58
 59    button {
 60        display: block;
 61        margin: 1em auto;
 62        padding: 0.75em 1.5em;
 63        font-size: 1rem;
 64        background-color: #007bff;
 65        color: white;
 66        border: none;
 67        border-radius: 6px;
 68        cursor: pointer;
 69        transition: background-color 0.3s ease;
 70    }
 71
 72    button:hover {
 73        background-color: #0056b3;
 74    }
 75
 76    #output {
 77        margin-top: 1em;
 78        background-color: #1e1e1e;
 79        color: #0f0;
 80        padding: 1em;
 81        border-radius: 8px;
 82        min-height: 200px;
 83        font-family: Consolas, monospace;
 84        font-size: 0.95rem;
 85        overflow-y: auto;
 86        white-space: pre-wrap;
 87    }
 88
 89    .highlight {
 90        outline: 3px solid #ffc107; /* yellow border */
 91        background-color: #fff8e1;  /* soft yellow background */
 92        transition: background-color 0.3s ease, outline 0.3s ease;
 93    }
 94
 95    .active {
 96        background-color: #28a745; /* green background */
 97        color: #fff;
 98        box-shadow: 0 0 10px rgba(40, 167, 69, 0.5);
 99        transition: background-color 0.3s ease, box-shadow 0.3s ease;
100    }
101  </style>
102</head>
103<body>
104    <div class="container">
105        <h1>JavaScript Console</h1>
106        <button id="executeBtn">Execute</button>
107        <div id="output"></div>
108    </div>
109
110    <script>
111        // Override console.log to display messages in the #output element
112        (function () {
113            // Override console.log
114            const originalLog = console.log;
115            console.log = function (...args) {
116                originalLog.apply(console, args);
117                const message = document.createElement('div');
118                message.textContent = args.map(String).join(' ');
119                output.appendChild(message);
120            };
121
122            // Override console.error
123            const originalError = console.error;
124            console.error = function (...args) {
125                originalError.apply(console, args);
126                const message = document.createElement('div');
127                message.textContent = args.map(String).join(' ');
128                message.style.color = 'red'; // Color error messages red
129                output.appendChild(message);
130            };
131        })();
132
133        document.getElementById('executeBtn').addEventListener('click', () => {
134            // Prevent multiple loads
135            if (document.getElementById('externalScript')) return;
136
137            const script = document.createElement('script');
138            script.src = 'javascript-web-worker.js';
139            script.id = 'externalScript';
140            //script.onload = () => console.log('javascript-web-worker.js loaded and executed.');
141            //script.onerror = () => console.log('Failed to load javascript-web-worker.js.');
142            document.body.appendChild(script);
143        });
144    </script>
145</body>
146</html>

Web Worker in JavaScript

Web Worker in JavaScript is a mechanism that allows code to run in a separate thread from the main thread. This allows heavy computations and long-running operations to be performed asynchronously, preventing the main thread from being blocked. By using Web Worker, the responsiveness of the user interface improves and the application's performance enhances.

The basic use of Web Worker

Let's take a look at the basic usage of Web Worker.

A new Web Worker is created by specifying a JavaScript file.

1// worker.js (created as a separate file)
2onmessage = function(event) {
3    // Receive a message
4    const data = event.data;
5    // Perform heavy computation or processing
6    const result = data * 2;
7    // Return the result to the main thread
8    postMessage(result);
9};
 1// Main thread (main.js)
 2const worker = new Worker('worker.js');
 3
 4// Send a message to the worker
 5worker.postMessage(10);
 6
 7// Receive a message from the worker
 8worker.onmessage = function(event) {
 9    console.log('Result from Worker: ', event.data); // Result: 20
10};
11
12// Error handling
13worker.onerror = function(error) {
14    console.error('Worker error: ', error);
15};
  • This code demonstrates the basic mechanism of using a Web Worker to request computation from the main thread and receive the result asynchronously. It sends 10 as a message to the Web Worker and receives 20 as the result message. The main thread and the Web Worker communicate by sending and receiving messages to request and receive processing results.

Basic functions

Web Worker provides the following basic features.

  • postMessage and onmessage Used to send and receive messages between the main thread and the Web Worker. Send data with postMessage and receive it with onmessage.
  • Thread Independence Web Worker operates completely independently of the main thread. Therefore, variables and functions defined in the main thread cannot be accessed. Required data needs to be passed via postMessage.
  • Script Import To load external scripts within a Web Worker, use importScripts().
1// mathUtils.js
2function double(n) {
3    return n * 2;
4}
1// worker.js
2importScripts('mathUtils.js');
3
4onmessage = function(event) {
5    const input = event.data;
6    const result = double(input); // mathUtils.jsの関数を使用
7    postMessage(result);
8};
 1// Main thread (main.js)
 2const worker = new Worker('worker.js');
 3
 4// Send a message to the worker
 5worker.postMessage(10);
 6
 7// Receive a message from the worker
 8worker.onmessage = function(event) {
 9    console.log('Result from Worker: ', event.data); // Result: 20
10};
11
12// Error handling
13worker.onerror = function(error) {
14    console.error('Worker error: ', error);
15};

Alternatively, you can also use import as shown below.

1// lib.js
2
3// Simulated CPU-intensive task
4export function doHeavyWork(n) {
5    return n * 2;
6}
1// worker.js
2import { doHeavyWork } from './lib.js';
3
4self.onmessage = (event) => {
5  const data = event.data;
6  const result = doHeavyWork(data);
7  self.postMessage(result);
8};
 1// Main thread (main.js)
 2const worker = new Worker('worker.js', { type: 'module' });
 3
 4// Send a message to the worker
 5worker.postMessage(10);
 6
 7// Receive a message from the worker
 8worker.onmessage = function(event) {
 9    console.log('Result from Worker: ', event.data); // Result: 20
10};
11
12// Error handling
13worker.onerror = function(error) {
14    console.error('Worker error: ', error);
15};
  • By specifying type: 'module' in the argument of new Worker, you can treat the worker as an ES module and use the import syntax.

Differences between Web Worker and async functions

Web Worker

Features
  • Thread Isolation Web Worker executes JavaScript code in a separate thread. This allows heavy calculation processing to be performed without blocking the main thread (UI thread).
  • Concurrent Processing Using Web Worker allows JavaScript programs to perform concurrent processing in multiple threads.
  • Message Communication The Web Worker and the main thread do not share data directly and exchange messages using postMessage and onmessage.
  • Cannot Access UI Web Worker cannot access the DOM, so it cannot directly manipulate the UI.
Use cases
  • It is suitable for heavy computation processes such as image processing, data analysis, and encryption.
  • It can be used when you do not want to block the main thread.

async

Features
  • Simplifying Asynchronous Processing The async function is a syntax to make asynchronous processing more readable, internally using Promise.
  • Single Thread All async functions run on the main thread. Therefore, you need to devise ways to avoid blocking the UI thread.
  • Optimal for I/O Operations It is suitable for asynchronous tasks such as network communication and file reading, but not for heavy computation.
Use cases
  • It is suitable for network communication such as API calls.
  • It is suitable for file reading and writing using browser APIs or Node.js.

Key Differences

Features Web Worker async
Execution Environment Separate thread Main thread
Purpose Parallel processing, offloading heavy computations Concise description of asynchronous operations
DOM Access Not possible Possible
Communication Method Message passing (e.g., postMessage) Not required (handled via direct function calls or await)
Use Cases Time-consuming computations, data analysis I/O operations, API calls

When to Use Each

For CPU-intensive tasks, you can use Web Worker to reduce the load on the main thread. On the other hand, for network communication or I/O operations, you can simplify your code using async/await.

By combining both appropriately, you can achieve efficient asynchronous processing.

Examples of Web Worker Usage

Example of offloading heavy computation

Next is an example of offloading heavy computations.

 1// worker.js
 2onmessage = function(event) {
 3    const num = event.data;
 4    const result = fibonacci(num);
 5    postMessage(result);
 6};
 7
 8function fibonacci(n) {
 9    if (n <= 1) return n;
10    return fibonacci(n - 1) + fibonacci(n - 2);
11}
1// Main thread
2const worker = new Worker('worker.js');
3
4worker.onmessage = function(event) {
5    console.log('Fibonacci result: ', event.data);
6};
7
8worker.postMessage(40); // Delegate heavy computation to the worker
  • This code is an example of using a Web Worker to separate and execute heavy tasks like Fibonacci sequence calculations from the main thread.

An example of specifying a task name

Next is an example of sending and receiving messages by specifying a task name.

 1// worker.js
 2self.onmessage = function(event) {
 3    switch (event.data.task) {
 4        case 'add':
 5            const result = event.data.a + event.data.b;
 6            self.postMessage({ task: 'result', value: result });
 7            break;
 8        default:
 9            self.postMessage({ task: 'error', message: 'Invalid Task' });
10    }
11};
 1// Main thread
 2const worker = new Worker('worker.js');
 3
 4worker.onmessage = function(event) {
 5    switch (event.data.task) {
 6        case 'result':
 7            console.log('Task result: ', event.data.value);
 8            break;
 9        case 'error':
10            console.error('Error: ', event.data.message);
11            break;
12    }
13};
14
15worker.postMessage({ task: 'add', a: 10, b: 20 });
  • This code is an example of dispatching processing based on the task name in the message, with the Web Worker returning calculation results or errors to the main thread along with the task name.

Notes

When using Web Worker, keep the following points in mind.

  • Cannot Access DOM Web Worker cannot manipulate the UI or access the DOM. DOM manipulation needs to be performed in the main thread.
  • Communication Overhead There is some overhead when exchanging data between the main thread and the Web Worker. This can affect performance, especially when exchanging large amounts of data frequently.
  • Same-Origin Policy Web Worker scripts are subject to the same-origin policy. Scripts cannot be loaded from different domains.

Using Web Worker can improve the performance and responsiveness of your application, but it’s important to use it appropriately considering constraints such as the inability to manipulate the DOM.

You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.

YouTube Video