The Web Workers API runs a script in a background thread separate from your HTML page’s main thread. Heavy work (big loops, parsing, crunching) can finish without freezing clicks, typing, or animations on the page.
What does this mean for an HTML page?
The main thread owns the DOM: buttons, inputs, and layout. A page script creates a Worker, sends work with postMessage, and when the result returns, updates HTML elements. The worker never touches document directly.
How does messaging work?
Both sides call postMessage(data) and listen with onmessage. The payload is copied (structured clone), not shared by reference—safe plain objects and arrays travel either way.
When should you use workers on a site?
Long CPU tasks that would make the page feel stuck. Skip workers for tiny work that finishes in a few milliseconds. Prefer dedicated workers for one page; shared and service workers cover multi-tab and offline cases.
Same origin.
Worker scripts must be served from the same origin as the HTML page (or a Blob URL you create).
No DOM in the worker.
Do not call document.getElementById inside the worker. Return data; paint the UI on the main thread.
Workers can fetch.
Background threads may use fetch / XMLHttpRequest (with limits). They can also spawn same-origin child workers.
Syntax
HTML / Script Syntax
Create a dedicated worker from a page script and exchange messages:
JS
var worker = new Worker("worker.js");
worker.postMessage({ n: 10 });
worker.onmessage = function (event) {
document.getElementById("out").textContent = event.data;
};
worker.onerror = function (err) {
console.error(err.message);
};
// worker.terminate();
JS
self.onmessage = function (event) {
var n = event.data.n;
postMessage(n * n);
};
HTML
<button type="button" id="start">Run in worker</button>
<p id="out"></p>
<script src="main.js"></script>
Reference
Core HTML Concepts
How workers relate to your webpage:
Concept
Role
Main (UI) thread
Parses HTML, handles events, updates the DOM
Worker
Dedicated background thread for one page script
postMessage / onmessage
Send and receive copied data between page and worker
event.data
Payload on the message event
onerror
Runtime errors inside the worker script
terminate()
Stop the worker immediately from the page
SharedWorker
Shared across same-origin windows / iframes
Service Worker
Network proxy for offline / push (different lifecycle)
Main thread vs worker
HTML page (main)
Worker
DOM / document
Yes
No
Update a <p>
Yes
Send data back instead
Heavy CPU loop
Freezes UI
Keeps UI responsive
Global object
window
self / worker scope
Approach
How to Use Workers with an HTML Page
Keep the UI on the page; push compute to the worker.
Build HTML controls (button, status <p>).
Feature-detect: typeof Worker !== "undefined".
Create new Worker("worker.js") (same origin).
On click, worker.postMessage(input).
In worker.onmessage, write event.data into the HTML.
Handle onerror; call terminate() when the page no longer needs the worker.
Goal
Pattern
Start worker
new Worker("worker.js")
Send work
worker.postMessage(value)
Show result in HTML
worker.onmessage = (e) => el.textContent = e.data
Stop worker
worker.terminate()
Inline demo worker
new Worker(URL.createObjectURL(new Blob([code])))
Try it
Live Preview
Click to square a number in a background worker, then show the result in the HTML below.
Creates a Blob worker, posts n, and writes n × n into the page.
Result
Not started.
worker.postMessage(n) → onmessage → update <p>
Code
HTML Examples
Five patterns: create a worker, message round-trip, errors, heavy loop, and a full HTML page. Try It demos use Blob workers so they run without a separate worker.js file.
Example 1 — Create a Web Worker
JS
if (typeof Worker === "undefined") {
alert("Web Workers not supported");
} else {
var worker = new Worker("worker.js");
console.log("Worker created");
}
Blob Worker embeds the worker script for demos / Try It.
Click posts work; onmessage fills the paragraph.
Sites in production usually keep worker.js as a separate file.
Edge Cases & Pitfalls
Most worker bugs are DOM access from the wrong thread or wrong script URLs.
dom
Touching the DOM in the worker
Fails. Return data with postMessage and update HTML on the main thread.
path
Wrong worker script URL
Must be same-origin and reachable. Check Network tab if the worker never starts.
clone
Non-cloneable values
Functions and DOM nodes cannot be posted. Send plain data (numbers, strings, plain objects).
leak
Never terminating workers
Call terminate() when leaving a page or finishing a one-shot job if you create many workers.
file
file: pages
Some browsers restrict workers from local files. Serve HTML over http(s) while learning.
overuse
Worker for tiny tasks
Startup and messaging cost can exceed the work. Use workers for truly heavy jobs.
Compatibility
Browser Support
Dedicated Web Workers are supported in all modern browsers. Always feature-detect before creating one.
✓ Baseline · Widely available
Workers for HTML pages
Background threads via new Worker() work across current browsers for same-origin page scripts.
100%Dedicated Worker
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
Web WorkersUniversal
Bottom line: Use dedicated workers to protect HTML UI responsiveness—feature-detect and keep DOM updates on the main thread.
Remember
Key Takeaways
Workers run heavy JS off the HTML page’s UI thread.
No DOM in the worker—update HTML after onmessage.
postMessage both ways; data is copied, not shared.
Feature-detect and prefer same-origin worker.js files in production.
One line: Page script creates a Worker → posts work → receives a result → updates the HTML—UI stays responsive.
Frequently Asked Questions
Web Workers run a JavaScript file in a background thread separate from the page’s main (UI) thread. Heavy work can finish without freezing buttons, scrolling, or animations on the HTML page.
No. Workers cannot access document, window, or parent. Send results with postMessage; the main page script updates HTML elements.
In a page script, call new Worker("worker.js") with a same-origin script URL. For single-file demos you can also create a Blob URL. Feature-detect with typeof Worker !== "undefined".
Both sides use postMessage to send data and onmessage to receive it. Data is copied (structured clone), not shared by reference.
Dedicated workers (one page), shared workers (several same-origin contexts), and service workers (network proxy / offline). This tutorial focuses on dedicated workers for HTML pages.
Use them for CPU-heavy tasks—large loops, parsing big files, image crunching—while the HTML UI must stay responsive. Skip them for tiny one-liners that finish instantly.