Home > Enterprise >  EventLoop with async/await in JavaScript
EventLoop with async/await in JavaScript

Time:01-29

I try to understand how JS processes asynchronous methods and finally I have come to async/await. Trying to get a full insight, I have created this example:

async function first() {
  console.log(9);
  await Promise.resolve(2).then((r) => console.log(r));
  console.log(0);
  await Promise.resolve(3).then((r) => console.log(r));
}

async function second() {
  console.log(10);
  await Promise.resolve(4).then((r) => console.log(r));
  console.log(11);
  await Promise.resolve(5).then((r) => console.log(r));
}
first();
second();
const promise = Promise.resolve("new Promise");
promise.then((str) => console.log(str));

//The output: 
//9
//10
//2
//4
//new Promise
//0
//11
//3
//5

So, I have a question, why does it have such an order, and how JS's EventLoop works with async/await

I tried to create some other examples with similar syntax but the result is the same

CodePudding user response:

Here is a simplified time table of the most important evaluated expressions, the callstack at that time, the promise job queue (with promise reactions):

Callstack Evaluation Job Queue
Script first() -
Script>first console.log(9) -
Script>first Promise.resolve(2).then() (r=2)=>console.log(r)
Script>first await <pending> (r=2)=>console.log(r)
Script second() (r=2)=>console.log(r)
Script>second console.log(10) (r=2)=>console.log(r)
Script>second Promise.resolve(4).then() (r=2)=>console.log(r)

(r=4)=>console.log(r)
Script>second await <pending> (r=2)=>console.log(r)

(r=4)=>console.log(r)
Script promise = Promise.resolve("new Promise") (r=2)=>console.log(r)

(r=4)=>console.log(r)
Script promise.then((str)=>console.log(str)) (r=2)=>console.log(r)

(r=4)=>console.log(r)

(str="new Promise")=> console.log(str)
Job (r=2)=>console.log(r) (r=4)=>console.log(r)

(str="new Promise")=> console.log(str)
Job>anonym console.log(2) (r=4)=>console.log(r)

(str="new Promise")=> console.log(str)

resume first()
Job (r=4)=>console.log(r) (str="new Promise")=> console.log(str)

resume first()
Job>anonym console.log(4) (str="new Promise")=> console.log(str)

resume first()

resume second()
Job (str="new Promise")=> console.log(str) resume first()

resume second()
Job>anonym console.log("new Promise") resume first()

resume second()
Job resume first() resume second()
Job>first console.log(0) resume second()
Job>first Promise.resolve(3).then() resume second()

(r=3)=>console.log(r)
Job>first await <pending> resume second()

(r=3)=>console.log(r)
Job resume second() (r=3)=>console.log(r)
Job>second console.log(11) (r=3)=>console.log(r)
Job>second Promise.resolve(5).then() (r=0)=>console.log(r)

(r=5)=>console.log(r)
Job>second await <pending> (r=3)=>console.log(r)

(r=5)=>console.log(r)
Job (r=3)=>console.log(r) (r=5)=>console.log(r)
Job>anonym console.log(3) (r=5)=>console.log(r)

resume first()
Job (r=5)=>console.log(r) resume first()
Job>anonym console.log(5) resume first()

resume second()
Job resum first() resume second()
Job>first - resume second()
Job resume second() -
Job>second - -

Some points to highlight:

  • When a then method is executed on a promise that is in a fulfilled state, a job is added to a job queue. When the script has been executed to completion the first job in the promise job queue is extracted and executed.

  • Be aware that when a then method is executed this creates a new promise that is pending, even when then is called on a resolved promise. That pending promise will only resolve when the callback passed as argument has been executed, and this happens via a job (so, asynchronously).

  • After the expression following an await is executed, the async function's running state is saved, and the function returns. This running state will be restored by a job that is queued when the awaited promise resolves.

Hope this clarifies a few things.

CodePudding user response:

This is:

async function first() {
  console.log(9);
  await Promise.resolve(2).then((r) => console.log(r));
  console.log(0);
  await Promise.resolve(3).then((r) => console.log(r));
}

Is the same as this:

function first() {
  console.log(9);
  return Promise.resolve(2).then((r) => console.log(r)).then(() => {
    console.log(0);
    return Promise.resolve(3).then((r) => console.log(r));
  });
}

function first() {
  console.log(9);
  return Promise.resolve(2).then((r) => console.log(r)).then(() => {
    console.log(0);
    return Promise.resolve(3).then((r) => console.log(r));
  })
}

function second() {
  console.log(10);
  return Promise.resolve(4).then((r) => console.log(r)).then(() => {
    console.log(11);
    Promise.resolve(5).then((r) => console.log(r));
  })
}
first();
second();
const promise = Promise.resolve("new Promise");
promise.then((str) => console.log(str));

Same with better numbering

function first() {
  console.log(1);
  return Promise.resolve('a').then((r) => console.log(4, r)).then(() => {
    console.log(7);
    return Promise.resolve('b').then((r) => console.log(9, r));
  })
}

function second() {
  console.log(2);
  return Promise.resolve('c').then((r) => console.log(5, r)).then(() => {
    console.log(8);
    Promise.resolve('d').then((r) => console.log(10, r));
  })
}
first();
second();
console.log(3)
const promise = Promise.resolve('e');
promise.then((str) => console.log(6, str));

  • Related