I was reading about nested promises and encountered this coding challenge in the tutorials. Can someone explain the execution order of this code?
new Promise((resolve) => {
new Promise((res) => {
console.log("c");
resolve(3);
res(2);
}).then((response) => console.log(response))
}).then((res) => console.log(res));
I have ran the code and the output was:
c
2
3
But I was expecting that the output should be this:
c
3
2
because the outer promise is resolved first and then the inner promise is resolved later.
3
Answers
In short, it’s because of the order that you’re calling
.then
.In the above code we enter the outer constructor, which immediately calls the outer function. This then creates the inner promise, calling the inner function. The inner function logs "c", then resolves the outer promise to 3, and then resolves the inner promise to 2.
So at this point we have 2 resolved promises, but no code that’s trying to do anything with them.
Having finished constructing the inner promise, we call
.then
on the inner promise. Since the promise is resolved, this queues up a microtask to run.Having finished constructing the outer promise, we call
.then
on the outer promise. Since the promise is resolved, this queues up a microtask to run.Now we’ve finished running all synchronous code. The call stack empties and microtasks run. These are executed first in first out, so the microtask related to the inner promise runs first, logging out 2. Then the remaining microtask runs and logs out 3.
In addition to Nicholas’ answer, you’re possibly being tripped up by the reuse of the identifier ‘res’. The first use in the inner Promise is as a callback, where it returns the value 2 to the Promise.
The second use on the final line is in a different scope, and is used as the parameter name in the .then() for the outer Promise.
If you replace both uses of ‘res’ on the final line with ‘outerPromiseResult’, it might help to clear things up.
The initial outer function invokes an inner function, which contains a
resolve(3)
call without an immediate return, followed by ares(2)
call. These calls are placed in the microtask queue to be executed once the call stack is clear. The inner function must complete before the outer function can fully conclude. Consequently, the microtask queue contains:res(2)
resolve(3)