GAP·MAP
← all breakdowns
JavaScriptEvent LoopMicrotasksPromisesmiddle level

Predicting JavaScript Event Loop Output

the question

How do you predict what JavaScript prints when code mixes synchronous calls, promises, `queueMicrotask()`, `async`/`await`, and timers?

what they're testing: The interviewer is testing whether you can trace asynchronous control flow by enqueue time instead of guessing from source order.

a strong answer

Start with everything that runs synchronously. The promise executor runs when new Promise(...) is called, and an async function runs normally until it reaches its first await. Promise handlers, queueMicrotask() callbacks, and code after await do not interrupt that work.

Once the current task has finished and the JavaScript stack is empty, the browser drains the microtask queue in scheduling order. await always yields, even for an already-fulfilled promise. If a microtask queues another microtask, the new one joins the back of the queue and still runs before the browser moves to another task.

Timers are tasks, not microtasks. A zero delay makes a timer eligible for a later event-loop turn; it does not make the callback immediate. After any timer callback completes, its microtasks are drained before another task runs. The browser may render between tasks too.

To trace a puzzle, write down the synchronous logs while noting exactly when each microtask and timer is scheduled. Then drain microtasks, run the next selected task, and repeat. Do not treat new Promise(executor) like .then(...): the executor runs now, while the handler waits.

Why it lands

  • Uses enqueue order as a repeatable tracing method.
  • Separates promise construction from promise handlers.
  • Explains nested microtasks and zero-delay timers without hand-waving.
  • Connects `await` continuations to the same microtask queue as promise reactions.

Where people slip

  • `Promise.resolve().then(...)` runs immediately because the promise is already resolved.
  • `setTimeout(fn, 0)` runs as soon as the synchronous lines finish, before promise handlers.
  • `await` makes the entire async function asynchronous, including the code before its first `await`.
  • All asynchronous callbacks share one FIFO queue, so source order decides the result.

If they push further

What happens when a microtask queues another microtask?

The callback joins the back of the microtask queue. It runs during the same microtask checkpoint because the queue keeps draining until it is empty.

Does `await Promise.resolve()` continue synchronously?

No. The async function yields to its caller, and the code after `await` resumes in a microtask even when the promise is already fulfilled.

Would the same ordering hold in Node.js?

Not for every snippet. Promise reactions and `queueMicrotask()` share a microtask queue in Node, but timers and input/output callbacks run through Node's event-loop phases. `process.nextTick()` uses a separate queue, and its top-level order relative to microtasks differs between CommonJS and ESM.

Sources

Now answer it yourself.

Reading a strong answer is easy. Producing one under pressure is the skill the interview tests. Gapmap grades your answer against the same bar an interviewer would.

was this useful?

beta

The interviewer part is in the works.

The diagnostic, personal maps, and AI mock interviews are being finished right now. The notes stay free either way. Leave an email and you'll get the first-cohort invite, plus a month of Pro when it opens.