The Event Loop
The problem
JavaScript runs on a single thread, yet needs to handle slow operations (network requests, timers, file reads) without freezing everything else while waiting — the event loop is the mechanism that lets one thread stay responsive by never blocking on anything slow.
Why now
Processes and threads already covered multi-threaded concurrency as one answer to 'do many things at once'; JavaScript's runtime takes a different approach entirely, and understanding it requires the call stack and queue vocabulary from memory-and-the-stack and stacks-and-queues to describe precisely instead of hand-wavingly.
Mental model
JavaScript runs code on a single call stack, one frame at a time. When it hits something slow (a timer, a network call), it hands that off to the browser/Node runtime and moves on — when the slow thing finishes, its callback doesn't run immediately, it waits in a queue until the call stack is completely empty. The event loop's whole job is one repeated check: 'is the stack empty? if so, pull the next queued callback and run it.'
Requires
- Execution Context & HoistingJavaScript Runtime
The event loop describes how and when execution contexts get pushed onto the call stack and run; you need the execution-context model already in place before describing what happens between contexts.
- Stacks & QueuesComputer Science Fundamentals
The event loop is precisely the interaction of a stack (the call stack) and a queue (the callback/task queue) — the exact two data structures already covered, now shown operating together as a real runtime mechanism.
Helps
- Memory, the Stack & the HeapComputer Science Fundamentals
The 'call stack' the event loop empties and refills is the same stack data structure already connected to function calls generally; this topic is a specific, observable instance of it.
Unlocks
Used in
- Every setTimeout, network request, and DOM event handler in browser and Node.js JavaScript
- Understanding why a long synchronous loop freezes a web page's UI entirely
- Explaining the difference between microtasks (promises) and macrotasks (setTimeout) and their ordering
- Debugging 'why did this callback run later/earlier than I expected'
Projects
- Write code mixing synchronous logs, setTimeout(fn, 0), and a resolved Promise's .then(), predict the execution order, then run it and explain any surprises
- Write a deliberately blocking synchronous loop and observe how it freezes a page's UI until it completes
Examples
- console.log('a'); setTimeout(() => console.log('b'), 0); console.log('c'); logs a, c, b — the timeout callback waits for the stack to empty even with a 0ms delay
- A tight synchronous loop that never returns control to the event loop will freeze a browser tab entirely
Resources
Mastery checklist
- I can explain the event loop using the call stack, task queue, and 'stack must be empty' rule
- I can predict the output ordering of mixed synchronous and asynchronous code
- I can explain why a synchronous loop blocks the entire runtime, including UI rendering
- I can explain the difference between microtasks and macrotasks and which runs first