Book 1 · Lesson 1.1

JavaScript single-threaded model

  • Explain why JavaScript has one call stack per tab
  • Predict console output for sync + async code
  • Relate the event loop to radar polling and SSE

Prerequisites: 0.6 · 0.10

JavaScript in the browser is single-threaded: one call stack, one heap, one event loop per tab. Async work feels parallel — but execution is still interleaved on that one thread.

Why one thread?

Browsers originally ran JS for small UI tweaks. A single stack keeps the DOM model simple: no data races on document from two threads at once.

Heavy work (network, timers) is delegated to the browser or runtime. When ready, callbacks return via the event loop.

The classic snippet

console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
console.log('D');

Output: A, D, C, B — not alphabetical order.

console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
console.log('D');

Run synchronous code. console.log('A') executes immediately on the call stack.

Call stack

  • log('A')

Microtask queue

  • empty

Macrotask queue

  • empty

Console output

  • A

Team Radar connection

UI behaviorEvent loop role
TanStack Query refetch every 5sMacrotask / fetch callback
SSE onmessage handlerMicrotask/macrotask when chunk arrives
SolidJS signal updateSync render phase after data arrives

When metrics “jump” on the dashboard, you’re watching the loop drain queues — not a second JS thread.

Teach-back prompt

Why can a long synchronous loop block SSE updates from painting?

Predict microtask order

Lesson 1.1 check

1. Classic demo output order?