Search code examples
javascriptasync-awaitpromise

Why is the execution order not sequentyla in promises and await functions in JavaScript?


I have a code:

async function hh(){
    const promise1 = new Promise((resolve,reject) => {       
        resolve("First promise");
    });

    const promise2 = new Promise((resolve,reject) => {
        resolve("Second promise");
    });

    promise2.then((a)=>console.log(a));
    console.log(await promise1);
    console.log("sync call");
 }
hh();

result of this code is:

  • Second promise
  • First promise
  • sync call

My first question why sync call is not on the first place?

Then I just deleted from the code console.log(await promise1);

So the code looks like this:

async function hh(){
    const promise1 = new Promise((resolve,reject) => {       
        resolve("First promise");
    });

    const promise2 = new Promise((resolve,reject) => {
        resolve("Second promise");
    });

    promise2.then((a)=>console.log(a));
    console.log("sync call");
 }
hh();

End result now is:

  • sync call
  • Second promise

So now sync call is on the first place, just beacuse I deleted the second call, why?


Solution

  • This is what happens in that code:

    First version

    promise1 and promise2 are promises in status fulfilled -- you could have used the Promise.resolve function instead of new Promise.

    promise2.then() registers a callback to be executed when the promise is fulfilled, which it is, so the callback is enqueued as a job in the promise job queue.

    await promise1 suspends the hh function and registers hh to be resumed when the promise is fulfilled, which it is, so the resume of hh is enqueued as a job in the promise job queue (which now has two entries).

    hh() returns a promise (that is ignored) and the JS call stack becomes empty. Now the event loop will extract the first job and execute it. This outputs "Second promise".

    Then the call stack is empty again. The event loop will extract the last job and execute it. This resumes the hh execution context, which executes the console.log and outputs "First promise". It then continues with "sync call". Note that these two console.log are executed in one synchronous sequence, so there is absolutely no way that they could have their outputs in a different relative order.

    Second version

    Here the await is missing, so there is no suspension of the hh execution context, and the promise job queue only has one entry.

    As hh will run to completion the output "sync call" is the first output -- no job got a chance to run yet.

    When hh() returns the JS event loop will pick up that one job and executes it. This is the callback that outputs "Second promise".