DOM & JavaScript
Events fire, your code runs
The renderer dispatches a DOM event (keydown, click, input) through the capture → target → bubble chain. Your JavaScript event handler fires and decides to make a network request.
How It Works
When a DOM event fires, it doesn't go straight to your handler. The event first travels down the DOM tree from the document root to the target element (capture phase), fires on the target itself, then travels back up to the root (bubble phase). At each node, any registered event listeners fire in order. Your addEventListener('click', handler) callback runs during the bubble phase by default.
JavaScript runs on a single thread in each renderer process, using an event loop to multiplex work. The loop processes macrotasks (setTimeout, I/O callbacks, UI events) one at a time. After each macrotask, all pending microtasks run (Promise callbacks, MutationObserver). Then the browser may run requestAnimationFrame callbacks and render a frame. This is why a long-running JavaScript function blocks the entire UI — there's only one thread, and it can't paint until your code finishes.
The Signal Flow
Key Concepts
Events propagate up the DOM tree from child to parent. This is why you can add one click handler to a parent <ul> and catch clicks on any child <li> — called event delegation.
The single-threaded execution model: pick one macrotask → run it → drain all microtasks → maybe render → repeat. Everything in the browser — events, timers, network callbacks, rendering — is scheduled through this loop.
Microtasks (Promises, queueMicrotask) run immediately after the current task — before rendering. Macrotasks (setTimeout, events) wait for the next loop turn. This is why await is faster than setTimeout(fn, 0).
JavaScript and rendering share one thread. A 100 ms JavaScript function means 100 ms of no rendering, no scrolling, no input handling. This is why Web Workers exist — offload heavy work to a separate thread.
Deep Dive
The three-phase event model
The W3C DOM event model has three phases because of a historical compromise. Netscape used event capturing (top-down), Internet Explorer used event bubbling (bottom-up). The W3C standardized both: capture runs first (down), then the target fires, then bubbling runs (up). Most developers only use the bubbling phase, but capture is essential for intercepting events before they reach their target — used by focus management, accessibility tools, and framework event systems.
How JavaScript engines optimize
Modern JS engines (V8, SpiderMonkey, JSC) use JIT compilation: they parse JavaScript to bytecode, interpret it first, then identify 'hot' functions and compile them to optimized machine code. V8's Turbofan compiler can produce code that runs within 2–5x of hand-written C++. Inline caches (ICs) remember the shapes of objects you access frequently, turning property lookups from hash table searches into direct memory reads. This is why consistent object shapes matter for performance.
Related Specs
Must-know specifications from the Browser Platform layer.
The spec behind every HTML page, form, and browser API. The canonical reference for how browsers actually parse and process HTML.
Every frontend framework (React, Vue, Svelte) ultimately produces DOM operations. Understanding the event model and tree structure prevents subtle bugs.
Every fetch() call and XHR request is governed by this spec. It also defines CORS behavior in detail.
CSS drives all visual layout. Key modules: Grid, Flexbox, Custom Properties, Cascade layers, Container Queries. The snapshot identifies what's stable vs experimental.
JavaScript is the execution model of the web. The spec is the canonical reference for language semantics — closures, coercion, prototype lookup, module resolution, and async scheduling.
Every component framework (React, Vue, Lit, Angular) either compiles to or interacts with these primitives. Shadow DOM is how browsers isolate component internals. Understanding the native model prevents framework lock-in.