The Event Loop, Visualized

async/await, unmasked — interactive event loop example

1async function order() {
2 console.log('ordering');
3 await Promise.resolve();
4 console.log('order arrived');
5}
6
7order();
8console.log('walk away');

Calling an async function is a NORMAL call: order() pushes onto the stack and starts executing synchronously.

1 / 7

Call stack

script
order()

Web APIs — browser land

The event loop — is the call stack empty? → drain the microtask queue first → then take one callback.

Microtask queue — priority

Callback queue

Console

Fig. — async/await, unmasked · step 1 of 7

What is going on here

async and await are syntax over the same promise machinery, and this scene shows the moment that makes it obvious: the function leaves the call stack mid-body. "ordering" prints, the function hits await, and it stops — control returns to the caller, which is how "walk away" prints before "order arrived".

What await really does is split the function in two. Everything before it runs synchronously, right up to the await expression itself. The remainder is packaged as a continuation and queued as a microtask when the awaited value settles. The function frame is suspended, not blocked: the stack unwinds completely and the thread is free.

This is why an async function never freezes the page, and why the useful mental model is "await is .then with better syntax". Two practical consequences follow: the code before the first await runs eagerly the moment you call the function, and every await costs at least one microtask tick even when the awaited value is already available.

Common questions

Does await block the main thread?

No. It suspends only the async function that contains it. The call stack unwinds and the event loop keeps handling timers, events and rendering while the awaited promise is pending.

What happens to code after an await?

It becomes a continuation that is queued as a microtask when the awaited value settles. That is why it runs after the rest of the synchronous code that followed the function call.

Does awaiting an already-resolved value still cost a tick?

Yes. Even await Promise.resolve() defers the remainder of the function by at least one microtask, so the code after it never runs synchronously.

Every question on one page →·Run your own code →

Embed this figure in your own post →

Drop this into any article or course page. It stays interactive — readers can step through it without leaving your site.