Why await pauses only the current function
await does not block the JavaScript execution thread, it suspends only the async function it sits in. The rest of the program, event handlers, timers and other async functions keep running, because await hands control back to the Event Loop.
Theory
TL;DR
- JavaScript runs code on a single thread but schedules work through the Event Loop queues.
awaitdoes not stop that thread, it freezes only the currentasyncfunction.- The engine wraps the rest of the function body into a microtask that runs once the promise settles.
- The call stack is cleared, so other code (timers, events, other functions) keeps executing.
- When the promise becomes
fulfilledorrejected, the function continues exactly at theawaitline. - This is an asynchronous pause, not a block: no OS threads and no
sleepare involved.
Quick example
async function task() {
console.log('Start');
await new Promise(r => setTimeout(r, 2000));
console.log('End');
}
task();
// This line runs immediately, the engine is not blocked
console.log('This code runs right away!');Output:
Start
This code runs right away!
(after 2 s)
Endawait suspends only the task() function, while the main code moves on. JS does not freeze: inside task() the engine simply creates a microtask that returns to the queue after the timer fires.
What happens under the hood
When the engine meets await promise, this is what it does:
- It suspends the execution of the current
asyncfunction. - It creates a microtask (a callback) that will continue the function once the promise settles.
- It returns control to the Event Loop and clears the call stack.
- The engine runs other work: other functions, event handlers, timers and so on.
- When the promise settles (
fulfilledorrejected), the microtask runs and the function resumes at the exact line whereawaitstood.
All of this is implemented through the microtask queue (PromiseJobs). The engine uses no extra threads and no real sleep.
Step by step in the Event Loop
| Stage | What happens |
|---|---|
| 1 | task() enters the Call Stack and runs the code up to await |
| 2 | At await the function is frozen and a microtask is created |
| 3 | The stack is cleared, other scripts keep executing |
| 4 | When the promise settles, the microtask goes back into the queue |
| 5 | After the current Event Loop tick, the remaining code of task() runs |
If await really blocked the thread, the whole of JavaScript would hang for those 2 seconds: not a single event handler and not a single setTimeout would fire. That does not happen: while task() waits, the Event Loop calmly processes other events.
Parallel async functions do not wait for each other
async function foo() {
console.log('foo start');
await new Promise(res => setTimeout(res, 1000));
console.log('foo end');
}
async function bar() {
console.log('bar start');
await new Promise(res => setTimeout(res, 500));
console.log('bar end');
}
foo();
bar();
console.log('main thread');Output:
foo start
bar start
main thread
(after 0.5 s) bar end
(after 1 s) foo endawait does not get in the way of other functions. Each function simply freezes until its own promise settles and then continues independently of its neighbour.
The resumption microtask and the order of output
async function demo() {
console.log('A');
await Promise.resolve();
console.log('B');
}
demo();
console.log('C');Result:
A
C
BWhy exactly this order:
Aruns synchronously, beforeawait;awaitstops the function and puts its continuation (B) into the microtask queue;- the main code reaches
C; - and only when the stack is empty does the engine run the microtasks, that is,
B.
A simple analogy: an
asyncfunction is like a TV series. Atawaitthat particular series is paused, but the other channels keep broadcasting. When the promise it waits for is ready, the episode continues from the exact frame where it stopped.
What await does and does not do
What await does | What it does not do |
|---|---|
Suspends only the current async function | Does not block the JavaScript thread |
| Returns control to the Event Loop | Does not prevent other tasks from running |
| Resumes execution once the promise settles | Does not freeze the whole application |
Is implemented through microtasks (PromiseJobs) | Does not use OS threads or sleep |
Common mistakes
- Believing that
awaitstops the whole page, and therefore avoiding it in code that reacts to events. - Confusing a suspended function with a blocked thread: a real block is a synchronous loop such as
while (Date.now() < end) {}, and that is what freezes the tab, because it never gives the stack back. - Putting
awaitinside a loop where the requests are independent: the function waits for them one by one, although they could all start together withPromise.all(). - Expecting two consecutive
awaitstatements to run in parallel. They are strictly sequential: the second starts only after the first has settled. - Forgetting that after
awaitthe code continues inside a microtask, so the log order differs from a top to bottom synchronous reading.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.