I wonder why the execution order is "0 1 2 3 4 5 6" instead of "0 1 4 2 3 5 6".
Promise.resolve().then(() => {
console.log(0)
return Promise.resolve(4)
}).then((res) => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1)
}).then(() => {
console.log(2)
}).then(() => {
console.log(3)
}).then(() => {
console.log(5)
}).then(() => {
console.log(6)
})
It happens that way because it takes the JavaScript interpreter multiple microtasks to unwrap the value (4
) from a returned promise.
That's because promises are built in a way that most of the time only one thing happens in each microtask. A notable example is that then
callbacks always run in a new microtask.
The second chain of promises is executed alternately with the first chain. Its presence doesn't change the result, but it highlights how many steps (microtasks) it takes for something to happen.
In this case, the following happens (disregaring the second chain of promises here):
then
callback logging 0
runs, and returns the promise resolved to 4
.then
method of the returned promise is called internally to extract its value.then
callback is called and receives the value 4
. The first promise is now fulfilled, it schedules its then
callback to be executed.then
callback is called, receiving and logging the value 4
.So, in total, it takes 4 microtasks to print the value 4, which matches what we see.
You can observe this behavior by returning a custom then
able object, that forwards its operations to a real promise (I changed the logged values here to better illustrate what's going on):
Promise.resolve().then(() => {
console.log('#1')
}).then(() => {
console.log('#2')
}).then(() => {
console.log('#3')
}).then(() => {
console.log('#4')
}).then(() => {
console.log('#5')
}).then(() => {
console.log('#6')
})
Promise.resolve().then(() => {
console.log(1)
const returnValue = Promise.resolve(4)
return {
then(rs, rj){
// This is "inside" `Promise.resolve(4).then()`
console.log(2)
returnValue.then(v => {
//This is "inside" the callback given by the interpreter
console.log(3)
rs(v)
})
}
}
}).then((res) => {
console.log(4)
})