Async and Await - How is order of execution maintained?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
async and await make asynchronous JavaScript read like synchronous code, but they do not remove the event loop. Order is maintained because JavaScript runs synchronous statements immediately, suspends an async function at each await, and later resumes that function through the promise microtask queue.
That means there are really two kinds of ordering to understand: the lexical order inside one async function, and the scheduling order between synchronous code, promise continuations, and timer callbacks. Most confusion comes from mixing those two models together.
What await Actually Does
When JavaScript reaches await somePromise, it does three things:
- Evaluates the promise expression right away.
- Suspends only the current
asyncfunction. - Schedules the remainder of that function to resume later, after the promise settles.
It does not block the thread, and it does not pause unrelated code.
The output is:
demo() starts immediately, prints A, pauses at await, and then resumes later. That later resumption is why 1 appears before B done.
Event Loop, Microtasks, and Timers
Promise continuations run as microtasks. Timer callbacks such as setTimeout run as macrotasks. After the current synchronous call stack finishes, JavaScript drains the microtask queue before taking the next macrotask.
Expected order:
An await continuation behaves like the promise continuation above. That is why code after await usually runs before setTimeout(..., 0) callbacks that were scheduled earlier in the same turn.
Sequential Versus Parallel Work
Inside an async function, two back-to-back await expressions create sequential execution. The second operation does not start until the first one completes.
If the operations are independent, start them first and await them later.
Both versions preserve the order of results in the returned array, but the second version finishes faster because the delays overlap.
That distinction explains why await often feels sequential: it preserves source-code order inside one function unless you explicitly create concurrency.
Why Business Logic Still Has Deterministic Order
If one statement appears after another inside an async function, JavaScript will not reorder those statements. The function may pause between them, but when it resumes, the remaining code continues in the original lexical order.
This gives you predictable control flow for dependent operations:
You still need to think about concurrent tasks that were started elsewhere, but within one async function the order of the statements themselves remains stable.
Error Flow and Early Exit
Rejected promises also affect execution order. If an awaited promise rejects, control jumps to the nearest catch, and statements after the failing await are skipped.
Output:
Understanding this control transfer is important when later statements seem to “run out of order” but were actually skipped.
Common Pitfalls
A common mistake is assuming await blocks the entire JavaScript environment. It only pauses the current async function, so other event-loop tasks can continue.
Another issue is accidentally serializing independent operations with one await after another. If the tasks do not depend on each other, start them concurrently and join them with Promise.all.
Developers also often use Array.prototype.forEach with an async callback and expect sequential behavior. forEach does not await each callback. Use for...of for sequential async loops.
Finally, remember that timers and promise continuations are scheduled differently. Code after await often runs before a zero-delay timer because microtasks are processed before the next macrotask.
Summary
- '
awaitpauses the currentasyncfunction, not the whole thread.' - The remainder of the function resumes through the promise microtask queue.
- Synchronous code runs first, then microtasks, then timer callbacks.
- Back-to-back
awaitcalls are sequential unless you start the work in parallel first. - Most ordering bugs come from misunderstanding the event loop rather than from
asyncandawaitthemselves.

