When run the below code snippet, it outputs 2,1. Since Promise is a micro-task and everything inside a promise should run before a macro-task (setTimeout), I expect that the output will be 1,2. So even if there is a macro-task inside a micro-task, I thought the output will be 1,2.
But it outputs 2,1.
What's the catch here? Why does it outputs 2,1 instead 1,2?
Promise.resolve().then(() => {
setTimeout(() =>{
console.log("1")
}, 0)
})
setTimeout(() => {
console.log("2")
}, 0)
The promise is a micro task and will get executed before timeout1, but timeout1 is already scheduled as a macro task.
When the promise resolves, timeout2 will get scheduled, but the macrotask Q already has timeout1 and as such this is already scheduled and will get executed first.
Promise.resolve().then(/* 1. */() => {
setTimeout(/* 4. */() => {
console.log("1") /* 8. */
}, 0)
/* 5. */
})
setTimeout(/* 2. */() => {
console.log("2") /* 6. */
/* 7. */
}, 0)
/* 3. */
The following task is added to the microtask queue. Let's call it "micro1":
() => {
setTimeout(() => {
console.log("1")
}, 0)
}
The task queues look like
The following macrotask is scheduled. Let's call it "macro1"
() => {
console.log("2")
}
The task queues look like:
The code finishes executing. The event loop picks the next task. The Microtask queue has a priority, the next task to execute is micro1.
The following macrotask is scheduled. Let's call it "macro2"
() => {
console.log("1")
}
The timeout is zero, therefore there is nothing to wait. The queue is first in, first out, therefore the task macro2 is added to the end. There is no higher priority just because it came from a microtask or anything like that.
The task queues look like:
Task finishes executing. The event loop picks the next task. The Microtask queue is empty, therefore it picks a task from the macrotask queue. Next task to execute is macro1.
The task prints "2" to the console.
Task finishes executing. The event loop picks the next task. The Microtask queue is empty, therefore it picks a task from the macrotask queue. Next task to execute is macro2.
The task prints "1" to the console.
This is the Eventloop (best Explenation I have ever seen): https://youtu.be/cCOL7MC4Pl0?t=487
console.log("1")
Promise.resolve().then(() => {
console.log("4")
setTimeout(() =>{
console.log("7")
}, 0)
console.log("5")
})
console.log("2")
setTimeout(() => {
console.log("6")
}, 0)
console.log("3")
The snipped might help you understand it
Promis.resolve().then() does the same as setTimout(0) so you basically write a timeout inside a timout and thus the eventloop has to loop over it twice