Detailed explanation
The event loop is the scheduling mechanism that lets JavaScript handle asynchronous work without blocking execution while waiting for timers, network responses, or user input. Within one execution agent, JavaScript executes synchronous code on a single call stack, one operation at a time. The browser or Node.js runtime manages asynchronous facilities outside that stack and schedules eligible callbacks for later execution. This does not mean the entire runtime is single-threaded: workers and runtime internals can perform work concurrently.
In browsers, a useful model is tasks, often informally called macrotasks, plus a microtask queue. Timer callbacks and many event callbacks run as tasks; promise reaction handlers and queueMicrotask callbacks run as microtasks. After a task finishes and the stack is empty, the runtime performs a microtask checkpoint, processing queued microtasks until the queue is empty, including microtasks added during that checkpoint. The browser may then update rendering before selecting another runnable task. This model is simplified: browsers have multiple task queues, not one universal FIFO macrotask queue, and rendering does not necessarily happen after every task.
In the supplied example, console.log(1) runs immediately, setTimeout registers a timer, and Promise.resolve().then(...) queues a reaction for an already-fulfilled promise. Then console.log(2) runs. Once the current script finishes, the microtask logs 3 before the timer task logs 4, producing 1, 2, 3, 4. However, saying “promises always resolve before setTimeout(0)” is incorrect: promise settlement depends on the operation behind it. Only eligible, queued promise handlers receive microtask scheduling priority at the relevant checkpoint. A zero-delay timer also means no requested delay, not immediate execution; runtime constraints and busy execution can postpone it.
Interviewers assess whether you can trace execution and explain the queueing rules rather than repeat a slogan. Long synchronous work blocks other callbacks, and repeatedly scheduling microtasks can starve tasks and rendering. Node.js follows the same broad distinction but has event-loop phases and a separate process.nextTick queue, so browser rules alone do not fully predict every Node.js ordering.
Key points to remember
- Synchronous JavaScript runs to completion on the current call stack.
- The host runtime manages timers, I/O, and callback scheduling.
- Promise reactions and queueMicrotask callbacks run at microtask checkpoints, which drain the queue.
- The example prints 1, 2, 3, 4 because the already-queued promise handler precedes the timer callback.
- Timer delays are not execution guarantees; browser task scheduling and Node.js phases differ.
Common mistakes candidates make
- Claiming promises always settle before timers, regardless of when their underlying operations finish.
- Treating setTimeout(fn, 0) as immediate execution or assuming asynchronous callbacks interrupt synchronous code.
- Assuming browsers and Node.js share one identical FIFO callback queue and scheduling algorithm.
Likely follow-up questions
What happens if a microtask schedules another microtask?
The new microtask is processed during the same checkpoint, after microtasks already queued. An unbounded chain can prevent the runtime from reaching subsequent tasks or rendering.
Does a Promise executor run asynchronously?
No: the executor passed to new Promise runs synchronously when the promise is constructed. Its then, catch, and finally handlers run asynchronously as promise reactions once eligible.
How does Node.js differ from the browser event loop?
Node.js organises work into phases, including timers, poll for I/O, and check for setImmediate callbacks. It also has a separate process.nextTick queue whose callbacks generally precede promise microtasks at normal callback boundaries; execution context, including ES-module evaluation, can affect observed ordering.
Interview tip: Trace the example through the call stack, microtask checkpoint, and timer task, then qualify the promise-versus-timer claim.
