skip to Main Content

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


  1. Execution Order:

    1. Synchronous code in main() executes first:

      • console.log('main'); prints main.
      • setTimeout(f1, 0); schedules f1 as a macro task.
      • Promise.resolve().then(() => console.log('r1')); schedules a micro task to print r1.
      • new Promise(resolve => setTimeout(resolve, 0, "Done!")).then((message) => console.log(message)); schedules a macro task that will resolve the promise.
      • f2(); prints f2.
      • console.log('hello'); prints hello.
      • setTimeout(f3, 0); schedules f3 as a macro task.
    2. Synchronous code outside main():

      • setTimeout(f4, 0); schedules f4 as a macro task.
    3. Microtasks (promises) are processed next:

      • Promise.resolve().then(() => console.log('r1')); prints r1.
    4. Macro tasks are processed in the order they were scheduled:

      • f4 prints f4.
      • f1 prints f1.
      • The promise resolved by the setTimeout in the new Promise prints Done!.
      • f3 prints f3.
    Login or Signup to reply.
  2. 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

    new Promise(resolve => setTimeout(resolve, 0, "Done!"))
    .then((message) => console.log(message));
    

    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search