JavaScript Web Workers


JavaScript Web Workers Interview with follow-up questions

1. What is a Web Worker in JavaScript?

A Web Worker runs JavaScript on a background thread, separate from the main/UI thread. Its purpose is to offload CPU-heavy work (parsing, image processing, crypto, large computations) so the main thread stays responsive and the UI doesn't freeze.

// main thread
const worker = new Worker('worker.js', { type: 'module' });
worker.postMessage({ numbers: [1, 2, 3] });
worker.onmessage = (e) => console.log('result', e.data);

What interviewers expect you to add:

  • No DOM access — a worker has no document/window, so it can't touch the UI directly; it returns results via messaging.
  • Communication is by message passing (postMessage/onmessage), and data is copied via the structured clone algorithm — workers don't share variables with the main thread by default.
  • Types: dedicated (one page), shared (multiple pages/tabs of an origin), and service workers (a proxy for caching/offline and push — a different use case).
  • Workers add startup and message-passing overhead, so they pay off for genuinely heavy work, not trivial tasks.
↑ Back to top

Follow-up 1

What are the types of Web Workers?

There are two types of Web Workers:

  1. Dedicated Web Workers: These workers are created using the Worker constructor and are dedicated to a single script file. They can communicate with the main thread using the postMessage method.

  2. Shared Web Workers: These workers are created using the SharedWorker constructor and can be shared between multiple script files or windows. They can communicate with the main thread and other workers using the postMessage method.

Follow-up 2

Can you explain how a Web Worker communicates with the main thread?

A Web Worker communicates with the main thread using the postMessage method. The worker can send messages to the main thread by calling postMessage and passing the message as an argument. Similarly, the main thread can receive messages from the worker by listening for the message event and accessing the message data from the event object. This allows for bi-directional communication between the worker and the main thread.

Follow-up 3

What are the limitations of Web Workers?

Web Workers have the following limitations:

  1. Web Workers cannot directly access the DOM or manipulate the UI. They are restricted to perform tasks in the background.

  2. Web Workers cannot access the window object or the global scope of the main thread.

  3. Web Workers cannot use some JavaScript APIs that are specific to the main thread, such as alert, confirm, and prompt.

  4. Web Workers have limited support for synchronous operations, as they are primarily designed for asynchronous tasks.

Follow-up 4

Why would you use a Web Worker instead of a regular JavaScript function?

You would use a Web Worker instead of a regular JavaScript function in the following scenarios:

  1. When you have computationally intensive tasks that can be offloaded to a separate thread, allowing the main thread to remain responsive.

  2. When you want to perform tasks in the background without blocking the UI, such as processing large amounts of data or performing complex calculations.

  3. When you want to improve the overall performance and responsiveness of your web application by utilizing parallel execution.

  4. When you want to separate the execution of code from the main thread to enhance code organization and maintainability.

2. How do you create a Web Worker?

Instantiate the Worker constructor with the URL of the worker script. In modern code, pass { type: 'module' } so the worker can use import:

// main.js
const worker = new Worker('worker.js', { type: 'module' });

worker.postMessage({ cmd: 'start', payload: [1, 2, 3] });
worker.onmessage = (e) => console.log('from worker:', e.data);
worker.onerror = (e) => console.error(e.message);
// worker.js
self.onmessage = (e) => {
  const result = e.data.payload.reduce((a, b) => a + b, 0);
  self.postMessage(result);
};

Points interviewers look for:

  • The worker file must be same-origin (or served with appropriate CORS); you can also create one from a Blob URL for inline workers.
  • Communication is postMessage/onmessage in both directions; the worker refers to its global scope as self.
  • { type: 'module' } enables ES module import inside the worker — preferred over the legacy importScripts().
  • A bundler-friendly modern form is new Worker(new URL('./worker.js', import.meta.url), { type: 'module' }).
↑ Back to top

Follow-up 1

Can you show an example of creating a Web Worker?

Sure! Here is an example of creating a Web Worker:

// main.js
const worker = new Worker('worker.js');

worker.onmessage = function(event) {
  console.log('Message received from Web Worker:', event.data);
};

worker.postMessage('Hello from main thread!');

// worker.js
self.onmessage = function(event) {
  console.log('Message received in Web Worker:', event.data);
  self.postMessage('Hello from Web Worker!');
};

Follow-up 2

What is the role of the 'postMessage' method in Web Workers?

The postMessage method is used to send messages from the main thread to a Web Worker, or from a Web Worker back to the main thread. It takes a single argument, which can be any serializable data. Here is an example of using the postMessage method:

// main.js
const worker = new Worker('worker.js');

worker.onmessage = function(event) {
  console.log('Message received from Web Worker:', event.data);
};

worker.postMessage('Hello from main thread!');

// worker.js
self.onmessage = function(event) {
  console.log('Message received in Web Worker:', event.data);
  self.postMessage('Hello from Web Worker!');
};

Follow-up 3

What happens if the specified JavaScript file in the Web Worker constructor does not exist?

If the specified JavaScript file in the Web Worker constructor does not exist, an error will be thrown and the Web Worker will fail to initialize. Make sure to double-check the file path and ensure that the file exists at the specified location.

3. What is the purpose of the 'onmessage' event handler in the context of Web Workers?

onmessage is the handler that fires whenever a message arrives via postMessage. It's the core of two-way communication between the main thread and a worker — each side listens with onmessage (or addEventListener('message', ...)) and sends with postMessage.

// inside worker.js — receive from main thread
self.onmessage = (event) => {
  const data = event.data;        // the payload sent from main thread
  const result = heavyWork(data);
  self.postMessage(result);       // send the result back
};
// main thread — receive from worker
worker.onmessage = (event) => {
  console.log('worker says', event.data);
};

Key details interviewers probe:

  • The payload is on event.data, not event itself.
  • Data is passed by structured clone — it's copied, not shared, so mutating it in the worker doesn't affect the original.
  • addEventListener('message', ...) is preferred when you need multiple handlers.
  • For large buffers, use transferable objects (postMessage(buf, [buf])) to move ownership instead of copying.
↑ Back to top

Follow-up 1

Can you show an example of using the 'onmessage' event handler?

Sure! Here's an example of using the 'onmessage' event handler in a Web Worker:

// In the main thread
const worker = new Worker('worker.js');

worker.onmessage = function(event) {
  console.log('Received message from Web Worker:', event.data);
};

worker.postMessage('Hello from main thread!');

// In the Web Worker (worker.js)
onmessage = function(event) {
  console.log('Received message from main thread:', event.data);
  // Perform actions based on the received data
};

In this example, the main thread creates a new Web Worker and assigns a function to the 'onmessage' event handler. When the Web Worker receives a message from the main thread, it logs the received data and performs actions based on it.

Follow-up 2

What type of data can be sent to a Web Worker using the 'postMessage' method?

The 'postMessage' method in Web Workers can send various types of data, including:

  • Primitives: strings, numbers, booleans
  • Objects: plain objects, arrays, typed arrays, JSON objects
  • Transferable objects: ArrayBuffer, MessagePort

It's important to note that objects and arrays are serialized and deserialized when sent between the main thread and the Web Worker, so any functions or non-serializable properties will be lost in the process.

Follow-up 3

How does the 'onmessage' event handler receive data from the main thread?

The 'onmessage' event handler in a Web Worker receives data from the main thread through the 'event' parameter. The received data can be accessed using the 'event.data' property. The 'event.data' property contains the message sent by the main thread, which can be of any type supported by the 'postMessage' method. The Web Worker can then perform actions based on the received data.

4. How do you terminate a Web Worker?

Call terminate() on the worker instance from the main thread. This immediately stops the worker, aborting any in-progress work without letting it finish:

const worker = new Worker('worker.js', { type: 'module' });

// ...later, stop it
worker.terminate();

Alternatively, the worker can shut itself down from inside its own scope:

// inside worker.js
self.close();

What interviewers expect you to add:

  • terminate() is abrupt — no cleanup runs, and pending postMessage results are lost. If you need a graceful shutdown, message the worker to finish and let it call self.close().
  • Always terminate workers you no longer need — an idle worker keeps its thread and memory alive, so forgetting to clean up leaks resources (a common bug when workers are created per-task).
  • After termination the instance can't be reused; create a new Worker if needed.
↑ Back to top

Follow-up 1

Can you show an example of terminating a Web Worker?

Sure! Here's an example of terminating a Web Worker:

// Create a new Web Worker
const worker = new Worker('worker.js');

// Terminate the Web Worker
worker.terminate();

Follow-up 2

What happens to the Web Worker's execution context when it is terminated?

When a Web Worker is terminated, its execution context is destroyed. This means that any ongoing tasks or code execution within the worker will be stopped immediately. Any resources held by the worker, such as memory or network connections, will also be released.

Follow-up 3

Can a terminated Web Worker be restarted?

No, a terminated Web Worker cannot be restarted. Once a Web Worker is terminated, it cannot be used again. If you need to perform additional work, you will need to create a new Web Worker instance.

5. Can Web Workers share data with each other directly?

Not directly by sharing variables. Each worker runs in its own isolated thread with its own memory, so they can't read or mutate each other's variables the way functions in one thread can. Communication happens by message passing, where the data is copied (structured clone), not shared.

Two ways workers exchange data:

// Relay through the main thread (dedicated workers)
workerA.onmessage = (e) => workerB.postMessage(e.data);

// Or use a SharedWorker / MessageChannel to connect them
const channel = new MessageChannel();
workerA.postMessage({ port: channel.port1 }, [channel.port1]);
workerB.postMessage({ port: channel.port2 }, [channel.port2]);

The exception interviewers want — genuine shared memory: a SharedArrayBuffer can be referenced by multiple agents simultaneously, so writes from one worker are visible to another (coordinate access with Atomics to avoid races).

const shared = new SharedArrayBuffer(1024);
worker.postMessage(shared); // both sides reference the same memory

This requires the page to be cross-origin isolated via the COOP (same-origin) and COEP (require-corp) headers. Without those, SharedArrayBuffer is unavailable and you're limited to copied messages. For moving (not copying) a large buffer to a single worker, use transferable objects: postMessage(buf, [buf]).

↑ Back to top

Follow-up 1

If not, how can data be shared between Web Workers?

Data can be shared between Web Workers using the postMessage() method. This method allows Web Workers to send messages to each other, including data. The data can be any serializable object, such as a string, number, array, or object. The receiving Web Worker can then access the data from the event object in its onmessage event handler.

Follow-up 2

What are the implications of the fact that Web Workers do not share data directly?

The fact that Web Workers do not share data directly has several implications. First, it means that each Web Worker can operate independently and in parallel, without interfering with each other's data. This can improve performance and responsiveness in web applications. However, it also means that data needs to be explicitly shared between Web Workers using the postMessage() method, which adds some complexity to the code. Additionally, since Web Workers do not share the same memory space, they cannot directly access each other's variables or functions.

Follow-up 3

Can Web Workers access the DOM?

No, Web Workers cannot directly access the DOM. The DOM (Document Object Model) is the programming interface for HTML and XML documents, and it is typically accessed and manipulated by JavaScript running in the main thread. Web Workers, on the other hand, run in separate threads and do not have access to the DOM. This is because direct access to the DOM from multiple threads could lead to synchronization issues and potential conflicts. However, Web Workers can communicate with the main thread using the postMessage() method, and the main thread can then access and manipulate the DOM based on the messages received from the Web Workers.

Live mock interview

Mock interview: JavaScript Web Workers

Intermediate ~5 min Your own free AI key

Your voice and your AI key never touch our servers; the key stays in this browser and is sent only to Google. Only your round scores are saved to track progress.