I recently encountered this question on Stack Overflow, asking about how the then method really works in JavaScript. The responder, Trincot, made the following comment:
The host will check which job queues have entries, giving precedence to job queues with high priority. A Promise job queue has a very high priority, typically higher than the event queue that deals with user interaction or other external events. So, the job that was placed in the queue at step 4 above is taken out of the Promise Job queue. This job will sequentially call the callback functions that have been registered as then callbacks (such as the one registered in step 7) on the myPromise object.
If I understood his explanation correctly, whenever the resolve function is invoked, JavaScript will schedule a microtask (or a job) in the job queue, which will execute all the callbacks passed to then, including chaining, when the call stack is empty. For example:
Promise.resolve("Hi")
.then(() => {
console.log("Hi");
})
.then(() => {
console.log("World");
});
In this case, the promise is resolved immediately, which means that a microtask will be scheduled immediately. When the then callbacks finish execution, the JS engine will check for any microtasks in the queue. Since the promise was resolved immediately, it will execute the microtask, which in turn executes all the handlers passed to the then method. As a result, the code will output "Hi" and "World".
However, why does this code output "1 3 2 4" instead of "1 2 3 4"?
const p1 = Promise.resolve();
const p2 = Promise.resolve();
p1.then(() => {
console.log(1);
}).then(() => {
console.log(2);
});
p2.then(() => {
console.log(3);
}).then(() => {
console.log(4);
});
I believe the code should output "1 2 3 4" instead of "1 3 2 4". This is because, when p1 and p2 resolve, two microtasks are enqueued. As the then callbacks finish execution, they add these callbacks to their internal lists. Once the call stack is empty, the JS engine selects the oldest task from the queue and executes it. This task should execute all the then handlers passed to that specific Promise instance. However, it doesn't seem to be happening as expected. Could someone explain to me the reason behind this behavior?
Thanks for your time and have a great day!