JavaScript Web Workers
Web Workers allow you to run JavaScript in background threads, separate from the main thread. This prevents heavy computations from blocking the user interface, keeping the page responsive.
What Are Web Workers?
A Web Worker is a JavaScript script that runs in a background thread. Workers can perform complex calculations, process data, or handle network requests without freezing the main UI thread.
// Without workers: heavy computation blocks the UI
function heavyComputation() {
let sum = 0;
for (let i = 0; i < 1000000; i++) {
sum += Math.sqrt(i);
}
return sum;
}
console.log('Starting computation...');
const result = heavyComputation();
console.log('Result: ' + result.toFixed(2));
console.log('This was blocking - UI would freeze!');
// With workers, this runs in a background thread
// and the UI stays responsiveCreating a Worker
To create a worker, you pass the URL of a JavaScript file to the Worker constructor. The worker file runs in a separate thread.
// Main script (app.js)
// const worker = new Worker('worker.js');
// Worker file (worker.js):
// self.onmessage = function(e) {
// const result = e.data * 2;
// self.postMessage(result);
// };
// Simulating worker communication
console.log('Main: Creating worker...');
console.log('Main: Sending data to worker');
// Worker would process in background
const workerInput = 42;
const workerOutput = workerInput * 2;
console.log('Main: Sent value: ' + workerInput);
console.log('Worker: Received and processed');
console.log('Main: Got result: ' + workerOutput);postMessage() and onmessage
Communication between the main thread and workers is done using postMessage() to send data and onmessage to receive data. Data is copied (structured cloning), not shared.
// Main thread sends data with postMessage()
// worker.postMessage({ task: 'calculate', data: [1,2,3] });
// Worker receives with onmessage
// self.onmessage = function(event) {
// const { task, data } = event.data;
// if (task === 'calculate') {
// const sum = data.reduce((a, b) => a + b, 0);
// self.postMessage({ result: sum });
// }
// };
// Main thread receives worker's response
// worker.onmessage = function(event) {
// console.log('Result: ' + event.data.result);
// };
// Simulating the full exchange
const message = { task: 'calculate', data: [1, 2, 3, 4, 5] };
console.log('Main -> Worker: ' + JSON.stringify(message));
const sum = message.data.reduce((a, b) => a + b, 0);
const response = { result: sum };
console.log('Worker -> Main: ' + JSON.stringify(response));
console.log('Sum: ' + response.result);Terminating Workers
Workers can be terminated from the main thread using worker.terminate() or from within the worker using self.close(). Terminated workers cannot be restarted.
// From main thread: immediate termination
// worker.terminate();
// From inside the worker: graceful shutdown
// self.close();
// Error handling
// worker.onerror = function(error) {
// console.log('Worker error:', error.message);
// console.log('File:', error.filename);
// console.log('Line:', error.lineno);
// };
console.log('worker.terminate() - kills from main thread');
console.log('self.close() - worker shuts itself down');
console.log('worker.onerror - handles worker errors');
// Best practice: send a shutdown message
// worker.postMessage({ type: 'shutdown' });
// In worker:
// if (e.data.type === 'shutdown') { self.close(); }
console.log('Best practice: send shutdown message first');Worker Limitations and Use Cases
Workers run in an isolated environment with some important limitations. They cannot access the DOM, window, or document objects. However, they can use many Web APIs.
| Available in Workers | NOT Available in Workers |
|---|---|
| XMLHttpRequest / fetch | DOM (document, window) |
| setTimeout / setInterval | document.querySelector() |
| JSON, Math, Array | alert(), confirm(), prompt() |
| WebSockets | Parent page variables |
| IndexedDB | localStorage / sessionStorage |
| importScripts() | UI manipulation |
// Use cases for Web Workers:
// 1. Heavy calculations
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
console.log('Fibonacci(20) = ' + fibonacci(20));
// 2. Data processing
const data = Array.from({length: 1000}, (_, i) => i);
const processed = data.filter(n => n % 2 === 0).map(n => n * n);
console.log('Processed items: ' + processed.length);
// 3. Image processing, encryption, sorting
// 4. Polling APIs in the background
// 5. Parsing large JSON files
console.log('Workers keep the UI thread free!');