Worker()
Spawn a thread
Create a background script with new Worker(url) or an inline Blob URL.

Web Workers run JavaScript on a background thread so heavy work does not freeze clicks, scroll, or animation on the main page. This tutorial covers creating a Worker, messaging with postMessage / onmessage, error handling, DOM limits, five examples (including inline Blob workers), and how Dedicated Workers compare to Shared Workers.
Spawn a thread
Create a background script with new Worker(url) or an inline Blob URL.
Send data
Pass jobs and results between the main thread and the worker.
Receive results
Listen for replies on both sides of the messaging channel.
Thread limits
Workers cannot touch document or window—update the UI on the main thread.
Catch failures
Surface worker runtime errors instead of failing silently.
Clean up
Stop a worker when you no longer need it to free resources.
Web Workers are a browser feature that runs JavaScript in background threads, separate from the main thread that paints the page and handles clicks.
Each worker has its own global scope (self) and communicates only through messages. That makes workers ideal for long calculations, parsing large files, and media processing—without freezing scroll or input.
JavaScript on the main thread is single-threaded for UI work. A multi-second loop freezes the page. Workers move that CPU load off the UI thread so the app stays responsive.
Heavy work runs off the main UI thread.
postMessage clones data between threads safely.
Update the page only from the main thread.
Dedicated Workers work in all modern browsers.
In short: create a Worker, send jobs with postMessage, receive results with onmessage, never touch the DOM inside the worker, and call terminate() when done.
Always feature-detect, then create a worker from a script URL:
if (typeof Worker === 'undefined') {
console.warn('Web Workers not supported');
} else {
const worker = new Worker('worker.js');
} In worker.js, listen and reply:
self.onmessage = function (event) {
const result = event.data * 2;
postMessage(result);
}; In the Try It editor you often have one HTML file. Put worker code in a string and create a Blob URL:
var code = 'self.onmessage = function(e) { postMessage(e.data * 2); };';
var worker = new Worker(
URL.createObjectURL(new Blob([code], { type: 'application/javascript' }))
); Send from the main thread; receive replies in onmessage:
worker.postMessage(5);
worker.onmessage = function (event) {
console.log('Received from worker:', event.data); // 10
}; Inside the worker, mirror the pattern:
self.onmessage = function (event) {
postMessage(event.data * event.data);
}; You can send plain objects: worker.postMessage({ action: 'sum', values: [1, 2, 3] }). The worker receives a deep copy (structured clone), not a shared reference.
| Task | Code pattern |
|---|---|
| Feature detect | if (typeof Worker !== 'undefined') { ... } |
| Create worker | const w = new Worker('worker.js') |
| Send to worker | w.postMessage(data) |
| Receive from worker | w.onmessage = (e) => e.data |
| Worker listens | self.onmessage = (e) => { ... } |
| Worker replies | postMessage(result) |
| Stop worker | w.terminate() |
new Worker(url)Spawn thread
postMessage()Both sides
onmessageEvent handler
self onlyWorker scope
Choose the right place to run work.
new Worker()One page, one background thread—the common choice for this tutorial.
new SharedWorker()Shared across tabs of the same origin; more complex messaging.
UI + light workBest for DOM updates and short tasks; avoid multi-second loops here.
Reach for a worker when CPU work risks freezing the UI.
Math loops, simulations, sorting large arrays.
JSON, CSV, and log files that take noticeable time.
Image resize, audio analysis, waveform generation.
Workers cannot update elements—do that on the main thread.
Key benefit: the page stays interactive while expensive work finishes in the background.
Catch runtime errors from the worker script with worker.onerror:
worker.onerror = function (error) {
console.error('Worker error:', error.message);
console.error('File:', error.filename, 'Line:', error.lineno);
}; Call worker.terminate() when finished to free memory. Create a new Worker if you need more jobs later.
Five starter demos. Use View Output to preview here, or open Try It Yourself to edit and run live (?tryit=1 through 5). Try Its use inline Blob workers so you do not need a separate worker.js file.
Feature-detect, then create a worker (file URL in production; Blob in Try It).
if (typeof Worker === 'undefined') {
alert('Web Workers not supported');
} else {
var worker = new Worker('worker.js');
console.log('Worker created');
} Main thread sends 5. Worker doubles it and sends back 10.
worker.postMessage(5);
worker.onmessage = function (event) {
console.log('Received from worker:', event.data); // 10
}; self.onmessage = function (event) {
postMessage(event.data * 2);
}; Log runtime errors that occur inside the worker script.
worker.onerror = function (error) {
console.error('Worker error:', error.message);
}; Sum many numbers in a worker so the page stays clickable. The Try It demo keeps a counter ticking while the worker runs.
self.onmessage = function (e) {
var total = 0, i;
for (i = 0; i < e.data; i++) total += i;
postMessage(total);
}; Click sends 10; the worker returns 100. Worker code lives in a Blob string:
<button id="start">Start Worker</button>
<p id="result"></p>
<script>
var worker = new Worker(URL.createObjectURL(new Blob([
'self.onmessage=function(e){postMessage(e.data*e.data);};'
], { type: 'application/javascript' })));
worker.onmessage = function (e) {
document.getElementById('result').textContent = 'Result: ' + e.data;
};
document.getElementById('start').onclick = function () {
worker.postMessage(10);
};
</script> Worker is available.Worker and provide a main-thread fallback for critical paths.js files in productionTransferable objects (ArrayBuffer) for zero-copy moves when transferring big buffersterminate() when a worker is idle for a long timeAvoid these mistakes when workers misbehave.
Workers cannot access document or window.
→ Post results to the main thread and update the UI there.
Message data is cloned, not shared.
→ Expect copies; use Transferables when you must move large buffers.
Startup and messaging overhead can outweigh the benefit.
→ Use workers when work risks blocking the UI for a noticeable time.
Idle workers still consume resources.
→ Call terminate() when the job pipeline is done.
Some restricted environments may not expose Worker.
→ Check typeof Worker !== 'undefined' and fall back on the main thread.
Pro Tip: if messages never arrive, confirm both sides set onmessage before the first postMessage, and that the worker Blob/URL is valid.
Confirm typeof Worker before creating a thread.
Browser loads the worker script on a background thread.
Main thread sends input data (cloned) to the worker.
Heavy logic runs without blocking UI events.
Main thread updates the DOM with the answer.
postMessage uses structured clone; functions and DOM nodes cannot be sent.Quick Takeaway: detect Worker, spawn a background script, exchange data with postMessage, keep the DOM on the main thread, and terminate when finished.
Dedicated Web Workers are a long-standing web standard supported in all modern browsers for background JavaScript threads.
Use Dedicated Workers for CPU-heavy work. Feature-detect with typeof Worker !== 'undefined'. Shared Workers have slightly different support and APIs.
Bottom line: Safe for production. Always feature-detect and keep a main-thread fallback for critical paths.
Web Workers keep pages responsive by moving expensive JavaScript off the main thread. You create a worker, exchange messages, handle errors, and update the DOM only from the main script.
Practice the five examples above—especially the inline Blob pattern used in Try It—then continue to the ASCII Table reference or revisit streaming with Server-Sent Events.
Remember: no DOM inside the worker, clone costs on every message, and terminate when idle.
Worker before creating oneonerror and empty/failed repliesdocument or window from a workerKeep the UI smooth with background threads.
Spawn a background script
CreateSend jobs and results
MessageUpdate UI on main thread
LimitsSurface worker failures
ErrorsContinue to the ASCII Table
PathWeb Workers run in a separate thread with no access to the DOM. Use postMessage() to send data and onmessage to receive results—structured cloning copies plain objects safely between threads. Dedicated Workers shipped in browsers years before SharedArrayBuffer and Atomics—message passing remains the simplest, safest concurrency model for most apps.
Browse character codes and related HTML entity references.
9 people found this page helpful