What happens between clicking "Pay Now" and the network request leaving the browser, event loop and microtasks included.
Click → DOM event dispatched (capture→target→bubble) → handler runs on the main thread → validation/state updates → fetch() called → browser builds the request, applies CORS/credentials/CSP checks, may do a preflight → DNS lookup → TCP handshake → TLS handshake → HTTP request bytes sent. The JS handler returns long before the response; the response callback is queued as a microtask.
This question traces a single user action all the way down the stack — it tests whether you understand the browser event model, the JS runtime, and the network layer as one continuous pipeline.
Phase 1 — The DOM event
- User clicks "Pay Now". The browser does hit testing to find the target element.
- A
clickevent is dispatched and travels in three phases: capture (window → target), target, bubble (target → window). Listeners fire along the way. - The event handler is a macrotask — it runs on the main thread, on the call stack.
Phase 2 — The JS handler runs
- Your handler executes synchronously: validate the form, maybe
e.preventDefault(), update UI state (disable the button, show a spinner), read the amount/token. - It calls
fetch("/api/pay", { method: "POST", body, headers }). fetchreturns a pending Promise immediately. The handler finishes and the call stack unwinds — the network request has not gone out yet from JS's perspective; JS just handed it to the browser.
Phase 3 — The browser prepares the request
- The browser's networking stack takes over (off the main thread):
- Builds the HTTP request (method, headers, cookies if
credentialsallows, body). - CORS check: for a cross-origin, non-simple request, it sends a preflight
OPTIONSfirst and waits forAccess-Control-Allow-*headers. - CSP / mixed-content checks — is this origin allowed by
connect-src? Is it HTTPS? - Service worker
fetchevent may intercept here. - Cache check (could short-circuit).
Phase 4 — The request leaves the machine
- DNS resolution — hostname → IP (cached at OS/browser level if seen recently).
- TCP handshake — SYN / SYN-ACK / ACK (skipped if a connection is reused/pooled).
- TLS handshake — for HTTPS: certificate exchange, key negotiation (1–2 RTTs, or 0-RTT with TLS 1.3 resumption).
- The HTTP request bytes are written to the socket — now the request has truly "left the browser."
Phase 5 — Coming back (briefly)
- Response arrives → browser parses headers, re-checks CORS → resolves the
fetchPromise. - The
.thencallback is scheduled as a microtask and runs when the stack is next empty — updating the UI ("Payment successful").
What separates a strong answer
- Knowing the event phases (capture/target/bubble).
- Knowing
fetchis async — the handler returns long before anything hits the network. - Naming CORS preflight, CSP, service worker as gates before the network.
- The DNS → TCP → TLS → HTTP ordering, and that connection reuse skips steps.
- The response callback is a microtask.
Senior framing
The senior version connects three mental models that are usually taught separately — the DOM event model, the event loop, and the network stack — into one timeline, and notes the async seam: the synchronous JS handler ends, the browser does the slow work, and the result re-enters JS as a microtask. Bonus: mention idempotency keys for the payment so a double-click doesn't double-charge.
Follow-up questions
- •What triggers a CORS preflight and what makes a request 'simple'?
- •How does connection pooling / keep-alive change this timeline?
- •How do you prevent a double-click from sending two payment requests?
- •Where could a service worker intercept this?
Common mistakes
- •Thinking the network request goes out synchronously inside the handler.
- •Skipping the CORS preflight / CSP checks.
- •Forgetting DNS/TCP/TLS happen before any HTTP bytes are sent.
- •Not mentioning the response callback is a microtask.
Edge cases
- •Reused keep-alive connection skips DNS/TCP/TLS entirely.
- •TLS 1.3 0-RTT resumption sends data on the first flight.
- •A service worker can fully intercept and serve from cache — no network at all.
- •Double-submit needs button disabling + an idempotency key server-side.
Real-world examples
- •Checkout/payment flows, form submissions, any fetch triggered by a click.