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 behavior | Event loop role |
|---|---|
| TanStack Query refetch every 5s | Macrotask / fetch callback |
SSE onmessage handler | Microtask/macrotask when chunk arrives |
| SolidJS signal update | Sync 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
Lab complete — nice work.