Ever seen this and wondered why the output changes just by reordering lines?
async function hi() {
return "there";
}
// Version A
const waitedhi = await hi();
console.log(waitedhi);
hi().then(res => console.log(res));
console.log("end");
vs
// Version B
hi().then(res => console.log(res));
const waitedhi = await hi();
console.log(waitedhi);
console.log("end");
π Same codeβ¦ different output. Why?
π§ The Hidden Mechanism: Microtasks
Both await and .then() use Promises, and both schedule work in the microtask queue.
π Key rule:
Microtasks run in the order they are added (FIFO)
β‘ What await really does
await hi();
is roughly:
hi().then(result => {
// rest of your code
});
So:
-
.then()β schedules a microtask -
awaitβ schedules a microtask (continuation)
π₯ Why order matters
Version A
-
awaitschedules continuation - resumes β logs
"there" -
.then()schedules another microtask -
"end"logs -
.then()runs
β
Output:
there
end
there
Version B
-
.then()β microtask A -
awaitβ microtask B - Run A β Run B
β
Output:
there
there
end
π§© The Bigger Picture: Event Loop
To fully understand this, you need 3 things:
1οΈβ£ Call Stack
- Executes synchronous code
- Runs line by line
- Example:
console.log("start");
2οΈβ£ Microtask Queue (High Priority)
- Promises (
.then,await) - Runs immediately after stack is empty
3οΈβ£ Macrotask Queue (Low Priority)
setTimeoutsetInterval- Runs after all microtasks are done
β‘ Golden Rule
JS finishes the call stack β runs ALL microtasks β then runs ONE macrotask
π§ͺ Full Example
console.log("start");
setTimeout(() => console.log("timeout"), 0);
Promise.resolve().then(() => console.log("then"));
await Promise.resolve();
console.log("end");
π Execution Flow
Step 1: Call Stack
start
Step 2: Queues
Microtasks: [then, await-resume]
Macrotasks: [timeout]
Step 3: Run Microtasks
then
end
Step 4: Run Macrotask
timeout
β Final Output
start
then
end
timeout
π― Final Takeaways
-
await= pause + schedule continuation as microtask -
.then()= directly schedules microtask - Microtasks always run before macrotasks
- Order of scheduling = order of execution
π¬ Once you understand this, async JavaScript stops feeling random and starts feeling predictable.
Top comments (0)