For that promise tricky question
I write here to learn, feel free to correct.
Good catch. The difference is:
in
foo, theawaitis directly insidefooin
two, theawaitis waiting on another async function’s promise
So in one case, foo queues its own continuation immediately. In the other, two cannot queue its continuation yet, because it is waiting for one() to finish first.
Case 1: direct await
async function foo() {
console.log("B");
await null;
console.log("C");
}
When execution reaches:
await null;
JavaScript does this:
converts
nulltoPromise.resolve(null)pauses
fooqueues the rest of
fooas a microtask
So yes, this part:
console.log("C");
gets queued right away.
Because foo is directly awaiting that value itself.
Case 2: two awaiting one()
async function two() {
console.log("two-1");
await one();
console.log("two-2");
}
When execution reaches:
await one();
JavaScript first has to evaluate one().
That call returns a promise. But at that moment, that promise is still pending, because one() has not finished.
So two does this:
call
one()get a pending promise back
pause
twoattach continuation logic to resume
twowhen that promise resolves
But two-2 is not placed in the microtask queue immediately, because the promise from one() is not resolved yet.
It only gets queued later, when one() completes.
Compare them side by side
foo
async function foo() {
console.log("B");
await null;
console.log("C");
}
At await null:
nullbecomes an already-resolved promiseso resume-
foocan be queued immediately
Queue:
[ resume foo -> print C ]
two
async function two() {
console.log("two-1");
await one();
console.log("two-2");
}
At await one():
first
one()runsone()returns a pending promisetwopausesbut resume-
twocannot be queued yetit will be queued only when
one()resolves
So initially, no two-2 microtask is added yet.
Why await null queues immediately
Because await always works with a promise-like value.
So:
await null
is basically like:
await Promise.resolve(null)
And since that promise is already resolved, the continuation can be scheduled right away as a microtask.
Not run immediately inline — but scheduled immediately.
Why await one() does not queue two-2 immediately
Because one() does not return an already finished value. It returns a promise that becomes resolved only after one finishes its own async work.
And in your example:
async function one() {
console.log("one-1");
await Promise.resolve();
console.log("one-2");
}
one() pauses at its own await, so the promise returned by one() stays pending until later.
So two() must wait.
Tiny timeline
foo
async function foo() {
console.log("B");
await null;
console.log("C");
}
Timeline:
print
Bhit
await nullqueue
C
two
async function two() {
console.log("two-1");
await one();
console.log("two-2");
}
Timeline:
print
two-1call
one()one()starts, then pausestwo()pauses waiting forone()’s promiselater
one()resumes and finishesonly then queue
two-2
Super short rule
awaitqueues the continuation when the awaited promise settlesif it is already resolved, that continuation can be queued immediately
if it is still pending, the continuation is queued later
So:
await null
→ queue continuation now
but
await one()
→ wait for one() to finish, then queue continuation
One-line mental model
await X does not mean “queue the next line now.” It means “pause here, and queue the next line when X is resolved.”
If you want, I can show this with a very small queue diagram for both snippets side by side.