Writing · MARGIN NOTESFront-End Development
What Interviewers Mean When They Ask About the Event Loop
The event loop is not magic timing. It is a scheduling model: stack, then microtasks, then macrotasks. Here is the interview mental model, the classic gotcha, and what to say out loud.
- Author
- Nicola Riker Urdaneta
- Published
- September 15, 2026
- Reading time
- 4 min read

Contents
In interviews, "explain the event loop" is rarely a request for a diagram from memory. Interviewers want to know whether you can predict the order of console.log when promises and timers mix, and whether you can explain why that order happens.
JavaScript runs on a single call stack. Async work does not mean multiple stacks racing. It means deferred callbacks wait in queues, and the event loop decides when those callbacks get to run.
Once you have that picture, the classic gotchas stop feeling random.
Why interviewers ask
The prompt usually looks like this: given a short script with console.log, Promise.then, and setTimeout(..., 0), what prints, and in what order?
They are testing three things at once:
- Do you know synchronous code runs to completion on the call stack before any queued callback?
- Do you know promise reactions are microtasks, while setTimeout callbacks are macrotasks (tasks)?
- Can you narrate one turn of the loop without waving at "async happens later"?
A correct ordering answer without a clear model is fragile. A clear model makes the ordering obvious.
Call stack (brief)
The call stack tracks which function is running right now. Each function call pushes a frame. When the function returns, that frame pops. Synchronous JavaScript is just stack frames going up and down. Objects and closures live on the heap; for this interview question you mainly need: while the stack is busy, queued callbacks wait.
Macrotasks (the task queue)
Macrotasks (often just called tasks) are work items scheduled for a later turn of the event loop. Common sources include:
- setTimeout and setInterval callbacks
- I/O callbacks in host environments that expose them to JS
- UI events in browsers (clicks, input, and similar)
setTimeout(fn, 0) does not mean "run immediately." It means "queue fn as a macrotask after at least 0ms." The callback still waits until the current script finishes, microtasks drain, and that timer task is next.
Microtasks
Microtasks are a higher-priority queue that drains after the current call stack clears, and before the next macrotask runs.
Common microtask sources:
- Promise then, catch, and finally reactions
- queueMicrotask(...)
- MutationObserver callbacks in browsers
That priority difference is the whole interview. Promise callbacks are not "just another timer."
One turn of the loop
A useful simplified model for interviews:
- Run the current script (or the next macrotask) until the call stack is empty.
- Drain the microtask queue completely. If a microtask schedules more microtasks, keep draining until it is empty.
- Take the next macrotask from the task queue and run it. Then go back to draining microtasks.
Hosts also do rendering and other platform work between turns. For ordering questions with console.log, promises, and timers, the stack → microtasks → next macrotask model is enough. Do not invent browser-only quirks as universal rules.
Classic gotcha: promise vs setTimeout
This is the demo interviewers expect you to walk through out loud.
console.log("A");
setTimeout(() => {
console.log("B");
}, 0);
Promise.resolve().then(() => {
console.log("C");
});
console.log("D");
// Output order: A, D, C, BWhy:
- A runs synchronously.
- setTimeout queues B as a macrotask.
- Promise.resolve().then queues C as a microtask.
- D runs synchronously. The script ends. The call stack is empty.
- Microtasks drain next, so C prints.
- Then the next macrotask runs, so B prints.
If someone says "B should come before C because setTimeout was written first," they are treating queue registration order as execution order across different queues. That is the wrong model.
async/await is promise sugar
An async function returns a promise. The body runs synchronously until the first await. After an await on a promise, the continuation is scheduled as a microtask (the same queue family as then callbacks).
async function demo() {
console.log("1 sync start");
await Promise.resolve();
console.log("3 microtask after await");
}
console.log("0 before call");
demo();
console.log("2 sync after call");
// Output order: 0, 1 sync start, 2 sync after call, 3 microtask after awaitMental model: await means "schedule the rest of this function as a microtask once the awaited promise fulfills," not "block the thread." The call stack still clears. Other sync work still runs. Then microtasks resume the async function.
What to say out loud in an interview
A strong answer sounds like this:
- JavaScript has one call stack. Sync code runs to completion first.
- Deferred work lands in queues: microtasks (promise reactions, queueMicrotask) and macrotasks (timers, many I/O and UI events).
- After the stack clears, the runtime drains all microtasks before the next macrotask.
- That is why Promise.then runs before setTimeout(..., 0), even if the timer was registered first.
- async/await is syntactic sugar over promises, so await continuations are microtasks.
Then walk the A/D/C/B demo. Concrete beats abstract every time.
Common wrong answers to avoid
- "setTimeout(fn, 0) runs immediately." No. It queues a macrotask.
- "Promises are multithreaded." No. Promise reactions still run on the same JS thread, as microtasks.
- "async/await blocks until the promise settles." No. It yields; other sync code and later microtasks continue the work.
- "Whichever callback was registered first always runs first." Not across different queues. Microtasks outrank the next macrotask.
- "The event loop is only a browser thing." Node and browsers differ in host details, but the microtask-before-next-task idea is the shared interview core.
Takeaways
- Call stack first: finish the current sync work.
- Then drain microtasks (promise reactions, queueMicrotask).
- Then run the next macrotask (setTimeout, many events).
- async/await pauses via microtasks, not by blocking the thread.
If you can narrate that loop and prove it with the promise vs setTimeout ordering, you are interview-ready on the event loop.