JavaScript async/await: Why Your console.logs Print in the "Wrong" Order

This course is for a developer who already writes JavaScript — you use .then(), you write async/await, you call setTimeout — but the order things run in still feels like magic. You log A before B in the source and B prints first; a .then() you wrote last somehow runs before a setTimeout(fn, 0) you wrote earlier; you can't say what await actually does to the line under it. The fix is not more syntax. It is one mental model: a single call stack, a microtask queue, and a task queue, with an event loop deciding who runs next. Once you can see those three places, the ordering stops being magic and becomes something you can predict on paper.

By the end you'll be able to (course objectives):

  • Describe the call stack and run-to-completion, and explain why synchronous code always finishes before any deferred callback.
  • Name the three moving parts — call stack, task queue, event loop — and say where a setTimeout callback waits and who runs it.
  • Explain why a promise .then() callback beats a setTimeout(fn, 0), using the microtask queue and its "drain fully before the next task" rule.
  • Explain what await actually does: it suspends only its own async function and schedules the rest as a microtask, without blocking the thread.
  • Predict the exact output order of a non-trivial snippet mixing sync logs, setTimeout, .then(), and await, then verify it in a real Node or browser console.

Prerequisites: You can write JavaScript functions, call console.log and setTimeout, and you have used .then() and async/await at least syntactically. No prior event-loop knowledge, no HTML-spec reading, and no framework or build tooling are assumed.

Practice environment: You run the snippets yourself in Node (node file.mjs) or a browser DevTools console — this course has no embedded runtime. Every prediction ends with you running the real code and checking the order against your call.

Lessons

#TopicYou'll learn
01Your setTimeout runs lastThe call stack, one thread, and run-to-completion — why setTimeout(fn, 0) waits
02Where the callback waitsThe task (macrotask) queue and the event loop that drains it when the stack is empty
03Promises jump the lineThe microtask queue, why .then() is a microtask, and why it beats setTimeout(fn, 0)
04await is .then() in disguiseAsync runs sync until the first await; the rest becomes a microtask; await never blocks
05Predict it, then prove itA repeatable procedure to call any snippet's order, verified in a real console

Sources listed in sources.md.