I had been struggling with the doubt , since in the event loop job queue has more priority than callback queue i.e, promises have more priority than setTimeout, then what about :
new Promise(resolve => setTimeout(resolve, 0, "Done!")).then((message) => console.log(message));
In the below code how is its priority decided:
function f1() {
console.log('f1');
}
function f2() {
console.log('f2');
}
function f3(){
console.log('f3');
}
function f4(){
console.log('f4');
}
function main() {
console.log('main');
setTimeout(f1, 0);
Promise.resolve().then(() => console.log('r1'));
new Promise(resolve => setTimeout(resolve, 0, "Done!")).then((message) => console.log(message));
f2();
console.log('hello');
setTimeout(f3, 0);
}
setTimeout(f4, 0);
main();
The output is:
main
f2
hello
r1
f4
f1
Done!
f3
2
Answers
Execution Order:
Synchronous code in
main()
executes first:console.log('main');
printsmain
.setTimeout(f1, 0);
schedulesf1
as a macro task.Promise.resolve().then(() => console.log('r1'));
schedules a micro task to printr1
.new Promise(resolve => setTimeout(resolve, 0, "Done!")).then((message) => console.log(message));
schedules a macro task that will resolve the promise.f2();
printsf2
.console.log('hello');
printshello
.setTimeout(f3, 0);
schedulesf3
as a macro task.Synchronous code outside
main()
:setTimeout(f4, 0);
schedulesf4
as a macro task.Microtasks (promises) are processed next:
Promise.resolve().then(() => console.log('r1'));
printsr1
.Macro tasks are processed in the order they were scheduled:
f4
printsf4
.f1
printsf1
.setTimeout
in the newPromise
printsDone!
.f3
printsf3
.There is no prioritization here. Prioritization is when the user agent (UA) is allowed to choose which task to run before another.
For microtasks they don’t have a choice at all, when the JS call stack is empty it has to execute the next microtask, no matter if the JS was executed from inside a task, after a callback execution, after another microtask execution.
Prioritization is a task thing, when the event loop picks one from the various task sources (step 2.1 in this algo). For instance UI tasks have generally more priority than timeout ones, so if there are both a pending UI task and a pending timeout task, the UA will execute the UI task first. If this runs JS, every time the JS call stack is empty there will be a microtask checkpoint.
So when you do
The timeout task will execute the JS that will resolve the Promise, and the resolving of the Promise will queue the microtask that will execute the JS logging the message. This microtask will be executed directly after the JS execution in the timeout task ends because the JS call stack is empty. So this means the microtask responsible to execute the JS that logs the message is itself inside the timer task. Only after that microtask is done running, the UA will continue executing the remaining of the steps it has to perform to end the timer task.
So as you can see microtasks are not in opposition with tasks, they are different things even though both do allow specs to make UAs execute stuff, but so is the whole event-loop’s processing model. And it makes no sense to talk about prioritization about these different things since when they’re executed is not comparable.