[Promise.reject(42), Promise.resolve(4)].forEach((item, i) => {
Promise.resolve(item)
.then(() => console.log("resolve", i))
.catch(() => console.log("reject", i));
});
Expected output:
reject 0
resolve 1
Actual output:
resolve 1
reject 0
2
Answers
Each call to
.then
or.catch
creates a new promise, which is dependent on the promise that came before. So your code is building two chains of promises. The reason for the behavior you’re seeing is that the logs are at different spots in the chain. The log for the reject case is one layer deeper in the chain than the log for the resolve case.The microtask queue controls which callback is going to execute next, and since both top level promises are starting in a settled state, there are going to be two entries in the queue. Once the first callback finishes, the promise below it can resolve and put itself into the queue, but it has to go behind the promise that’s already in the queue from the other stack. In other words, resolving the promises is going to zig zag between the two stacks: reject1 -> resolve1 -> reject2 -> resolve2 -> reject3 -> resolve3 (the bold ones are where the logs are).
So it might be looking at the rejected stack first at each layer, but it has to go deeper before it will get to the
.catch
which has the console.log.If you did the following change, then it would work as you expect (
.then
takes a second parameter to handle the catch case):I wrote a sample using finally instead of .catch to determine when the message is logged. I think it has something to do with the hierarchy of compiling.