Frontend Development 27 min read

Master JavaScript’s Single Thread: From Browser Processes to the Event Loop

This article systematically explains how browsers use multiple processes and threads, how the rendering pipeline works, why JavaScript runs on a single thread, and how the event loop, macrotasks, microtasks, timers, and Web Workers interact to affect performance and stability.

Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
Master JavaScript’s Single Thread: From Browser Processes to the Event Loop

Distinguish Process and Thread

A process is an independent OS resource (a factory) while a thread is a worker inside that process (a worker in the factory). In a browser each process has its own memory space; threads within the same process share that memory.

<code>- Process is a factory with independent resources
- Threads are workers that cooperate inside the factory
- One process can contain one or more threads</code>

Browser Is Multi‑Process

Opening a new tab creates a separate renderer process; the main Browser process coordinates UI, networking, and other tabs. Typical processes include the Browser (main) process, Renderer processes (one per tab), GPU process, and plugin processes.

Browser process handles UI, tab management, and resource allocation.

Renderer process parses HTML/CSS, builds the render tree, and paints.

Communication: Browser process receives a request, forwards it via RendererHost to the Renderer, which performs rendering and sends the result back for display.

Thread Relationships in the Browser Engine

GUI Rendering Thread

Responsible for parsing HTML/CSS, building the DOM and render trees, layout, and painting. It is mutually exclusive with the JavaScript engine thread.

JavaScript Engine Thread

Executes JavaScript code (e.g., V8). While it runs, the GUI thread is paused; UI updates are queued until the engine becomes idle.

Event Trigger Thread

Managed by the browser, it receives events (clicks, AJAX responses, timers) and pushes callbacks onto the task queue for the JS engine.

Timer Thread

Handles

setTimeout

and

setInterval

timing so that the single‑threaded JS engine is not blocked.

Async HTTP Thread

Performs network requests; on state change it posts an event to the task queue.

WebWorker and SharedWorker

WebWorker runs in a separate thread created by the browser (cannot access DOM). SharedWorker runs in its own process and can be shared across multiple renderer processes.

Simple Browser Rendering Flow

Parse HTML → build DOM tree.

Parse CSS → build render tree.

Layout (calculate sizes/positions).

Paint (rasterize pixels).

Composite layers via GPU and display.

After rendering, the

load

event fires;

DOMContentLoaded

fires earlier when only the DOM is ready.

CSS Loading and Layers

CSS loads asynchronously and does not block DOM parsing, but rendering (building the render tree) waits for CSS because style information is required.

Layers: normal layers belong to the default composite layer; hardware‑accelerated elements (e.g., using

translate3d

,

opacity

) create separate composite layers that are rasterized independently, improving performance when used sparingly.

From Event Loop to JavaScript Execution

JavaScript tasks are divided into synchronous (executed on the main call stack) and asynchronous (queued by the event‑trigger thread). When the call stack is empty, the engine drains the task queue, executing callbacks.

Timers

setTimeout

schedules a callback via the timer thread; the minimum delay is 4 ms per the HTML spec.

<code>setTimeout(function(){ console.log('hello!'); }, 1000);
console.log('begin');</code>

Output order:

begin

hello!

.

macrotask vs microtask

Macrotasks include the main script,

setTimeout

,

setInterval

, etc. After each macrotask, the engine runs all pending microtasks (Promises,

process.nextTick

) before rendering.

<code>console.log('script start');
setTimeout(()=> console.log('setTimeout'), 0);
Promise.resolve().then(()=> console.log('promise1')).then(()=> console.log('promise2'));
console.log('script end');</code>

Execution order:

script start

,

script end

,

promise1

,

promise2

,

setTimeout

.

Conclusion

Understanding the full browser pipeline—from process isolation, thread cooperation, rendering steps, to the event loop and task queues—helps developers write performant, non‑blocking JavaScript and avoid common pitfalls such as long‑running scripts, excessive layer creation, or misuse of timers.

performanceWeb WorkersBrowser Architectureevent-loop
Tencent IMWeb Frontend Team
Written by

Tencent IMWeb Frontend Team

IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.