Suggest an editImprove this articleRefine the answer for “Why a Web Worker has no DOM access”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**A Web Worker cannot see the DOM because the DOM is not thread safe and lives only on the main (UI) thread together with the Render Tree.** Any change to a node triggers a style recalculation, a layout pass and a repaint, and those steps have to happen in a strictly defined order. If two threads edited the same tree at once, you would get data races, the browser would have to block the main thread to keep things consistent, and the Event Loop would become unpredictable. So a worker runs in an isolated sandbox with no `window`, `document`, `localStorage` or `alert()`, and talks to the main thread only through `postMessage()` / `onmessage`. The worker computes; only the main thread updates the DOM. **Key point:** the DOM is tied to rendering and single threaded by design, so a worker returns its result as a message and the main thread changes the interface.Shown above the full answer for quick recall.Answer (EN)Image**A Web Worker has no DOM access because the DOM is not thread safe and is synchronously tied to page rendering, which lives only on the main (UI) thread.** The worker runs in an isolated sandbox and hands its result to the main thread as a message; the main thread is the one that changes the interface. ## Theory ### TL;DR - The DOM is a huge tree of objects that the browser keeps in memory and synchronously ties to the visual presentation of the page (layout plus render). - The DOM and the Render Tree exist only on the main thread; a worker has its own JS engine instance and no connection to the renderer. - Simultaneous access from several threads would produce data races and browser crashes. - Rendering cannot be parallelised: styles, layout and paint have to run in a strict order. - Isolation is also a security feature: no `window`, `document`, `localStorage` or `alert()`. - There is exactly one interaction model: the worker computes and sends the result, the main thread updates the DOM. ### Quick example ```javascript // main.js const worker = new Worker('worker.js'); worker.postMessage('calculate'); worker.onmessage = (e) => { document.querySelector('#result').textContent = e.data; }; ``` ```javascript // worker.js onmessage = (e) => { const result = heavyCalculation(); postMessage(result); }; ``` The worker does the computation and sends the result back, and the main thread updates the DOM if it needs to. ### Where the DOM lives and how the browser is built The DOM (Document Object Model) is a huge tree of objects that the browser keeps in memory and synchronously ties to the visual presentation of the page (layout plus render). When JavaScript changes something in the DOM (`element.textContent`, `style`, `appendChild` and so on): - the browser immediately updates its internal structures, - rebuilds the layout, - repaints the elements on screen. All of that happens on the browser's main (UI) thread. A simplified diagram: ```text +--------------------+ | Main thread (UI) | | |- JS Engine | <- has DOM access | |- Render Tree | <- responsible for display | +- Event Loop | +--------------------+ | v +--------------------+ | Web Worker Thread | | +- JS Engine | <- no DOM, no window/document +--------------------+ ``` The DOM and the Render Tree exist only on the main thread. Every Web Worker is an isolated thread: it has its own copy of the JS engine, but no link to the page renderer. ### Why workers cannot be given DOM access #### 1. The thread safety problem The DOM was never designed for concurrent access from several threads. > If two threads start changing the same element at the same time, you get data races and browser crashes. JS is single threaded for a reason: that is what makes DOM operations deterministic and safe. #### 2. UI rendering cannot be parallelised Changing the DOM means changing the interface. The browser has to: - recalculate styles (CSSOM), - rebuild the layout, - update the render layers (paint and composite). These operations have to happen in a strictly defined order. If several threads changed the DOM at once, the browser would have to synchronise all of them, and that would destroy performance. #### 3. Security and isolation (sandbox) Web Workers are isolated in a separate sandbox: - they cannot see `window`, `document`, `localStorage`; - they have no access to `alert()`, `confirm()`, `prompt()`; - they cannot read or change page content directly. This protects the site from accidental or malicious changes to the interface and to user data. #### 4. The message based interaction model Instead of direct DOM access, workers talk to the main thread through `postMessage()`. The worker computes and sends the result, and the main thread decides what to display. #### 5. Performance and predictability If a worker had DOM access: - every change would require synchronisation between threads; - the browser would have to block the main thread to protect its data; - the Event Loop would become unpredictable. In other words, workers exist precisely to take load off the UI, not to reach into it directly. ### What a worker can do instead of touching the DOM Workers do not render the interface, but they can: - compute, parse and filter large data sets; - work with `fetch`, `WebSocket`, `IndexedDB`; - run machine learning and cryptography; - process images, files and audio; - synchronise data with the server. All of that without freezing the interface. ### How to update the DOM from a worker after all Through messages: ```javascript // worker.js onmessage = () => { postMessage({ type: 'updateUI', text: 'Data is ready!' }); }; ``` ```javascript // main.js worker.onmessage = (e) => { if (e.data.type === 'updateUI') { document.querySelector('#status').textContent = e.data.text; } }; ``` The worker says what should be done, and the UI thread is the one that actually changes the DOM. A simple analogy: > Imagine the main thread is a surgeon and the Web Worker is an assistant in the lab. The assistant can count, analyse and prepare the data, but cannot touch the patient (the DOM) directly. The assistant just hands the results to the surgeon, who then makes the change carefully. Summary: | Question | Answer | | --- | --- | | Why does a worker have no DOM access? | Because the DOM is not thread safe and is tied to the UI | | Where does the DOM live? | Only on the browser's main thread | | What does a worker do? | Computation, data processing, network requests | | How does it talk to the main thread? | Through `postMessage` / `onmessage` | | Who updates the DOM? | Only the main thread | ### Common mistakes - Reaching for `document` or `window` in worker code and being surprised by a `ReferenceError`. The worker has a different global object, `self` (`DedicatedWorkerGlobalScope`). - Treating the restriction as a formality that can be worked around. It cannot: the worker thread simply has no DOM and no Render Tree. - Moving the interface update itself into the worker instead of the computation. The win comes only from offloading heavy calculations; the DOM is updated on the main thread either way. - Sending hundreds of tiny messages from the worker, one per step. Each message means serialisation plus a task in the main thread's queue, so accumulate the result and send it in batches. - Confusing "no DOM" with "no API at all". `fetch`, `WebSocket`, `IndexedDB`, `setTimeout` and `crypto` are all available in a worker. - Counting on `localStorage` to share data. It does not exist in a worker; `IndexedDB` is the right tool for shared state.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.