What is the JavaScript event loop?
The event loop is how JavaScript handles asynchronous code - it picks callbacks from a queue and runs them one at a time on a single thread.
JavaScriptAsync
Overview
JavaScript is single-threaded - only one piece of code runs at a time. The event loop is the mechanism that lets JavaScript handle async operations (timers, network requests, user events) without blocking. When async work completes, its callback is placed in a queue; the event loop picks it up once the call stack is empty.
Key Points
- β’Call stack: where synchronous code executes. Only one frame runs at a time.
- β’Web APIs (browser) / Node.js APIs: handle async work (setTimeout, fetch, fs) off the main thread.
- β’Task queue (macrotask): holds callbacks from `setTimeout`, `setInterval`, `I/O`.
- β’Microtask queue: holds Promise `.then` callbacks and `queueMicrotask`. Runs before the next macrotask.
- β’Order: call stack empties β all microtasks run β one macrotask runs β repeat.
Examples
Execution order - the classic puzzle
javascriptconsole.log('1 - synchronous');
setTimeout(() => console.log('2 - setTimeout (macrotask)'), 0);
Promise.resolve().then(() => console.log('3 - Promise microtask'));
console.log('4 - synchronous');
// Output:
// 1 - synchronous
// 4 - synchronous
// 3 - Promise microtask β microtasks run before macrotasks
// 2 - setTimeout (macrotask)Even with a 0ms delay, setTimeout runs after all microtasks.
Why blocking the main thread is bad
javascript// This blocks the thread for 3 seconds - UI freezes, no events processed
const end = Date.now() + 3000;
while (Date.now() < end) { /* busy-wait */ }
// Instead, use setTimeout or async APIs that don't block the event loopMicrotasks vs macrotasks with async/await
javascriptasync function run() {
console.log('A');
await Promise.resolve(); // pauses here, queues a microtask
console.log('B'); // runs in the microtask queue
}
run();
console.log('C');
// Output: A β C β BPro Tip
The practical takeaway: Promises (and `await`) resolve before `setTimeout`, even a 0ms timeout. This is because Promises use the microtask queue which always drains before the next macrotask. This matters for test ordering and sequencing async logic.