Home > OS >  Multiple async/await event loop order
Multiple async/await event loop order

Time:01-03

I got my head spinning off while learn asynchronous javascript. I have following code in async function:

const promise1 = () => {
  return new Promise((resolve, _reject) => {
    setTimeout(resolve, 3000);
  });
};
const promise2 = () => {
  return new Promise((resolve, _reject) => {
    setTimeout(resolve, 1000);
  });
};
await promise1();
console.log(1);
await promise2();
console.log(2);

It's work as i expect: "Wait for 3 seconds,do something synchronous,then wait 1 seconds and do something also synchronous". But if i change my both constants from anonymous function expression to Promise constructor

const promise3 = new Promise((resolve, _reject) => {
  setTimeout(resolve, 3000);
});
const promise4 = new Promise((resolve, _reject) => {
  setTimeout(resolve, 1000);
});

and call it as

await promise3;
console.log(3);
await promise4;
console.log(4);

my logic fails - second console.log(3) execute immediatelly without 1 second delay.

But again, if i return to first code and change timeout delay so that first delay will be less than second (i.e. first timeout delay 2000ms and second will be 3000) - second console.log(2) execute after difference time between 3000-2000=1000ms.

Can someone detailed explain how it works? I figure out,that's all about micro and macrotask in event loop, but don't understand, why i got this result.

P.S. I know, that both await can be replaced by:

delay(ms1)
.tnen(() =>{
  console.log('some1');
  return delay(ms2);
})
.then(() =>{
  console.log('some2')
})

Just need to understand deep mechanism of event loop with async\await;

CodePudding user response:

I figure out,that's all about micro and macrotask in event loop...

Not really. The key thing is that the Promise constructor calls the function you pass it (the promise executor function) immediately and synchronously. So the timer starts when you do new Promise, not later when you use await, so you're starting both timers one right after the other. In contrast, your first code block doesn't call new Promise to start the second timer until after the first timer has fired, because you're awaiting the first result before calling promise2() to get the promise for the second timer (which is what starts it).

Let's see that in action by adding some logging (I've changed promise1 to function and promise2 to function2, since they aren't promises, they're functions):

(async () => {
    const start = Date.now();
    const log = (...msgs) => console.log(String(Date.now() - start).padStart(4, "0"), ...msgs);

    const function1 = () => {
        log("function1 called");
        return new Promise((resolve, _reject) => {
            log("starting 3000ms timer");
            setTimeout(() => {
                log("fulfilling 3000ms timer");
                resolve();
            }, 3000);
        });
    };
    const function2 = () => {
        log("function1 called");
        return new Promise((resolve, _reject) => {
            log("starting 1000ms timer");
            setTimeout(() => {
                log("fulfilling 1000ms timer");
                resolve();
            }, 1000);
        });
    };
    log("Calling and waiting on function1");
    await function1();
    log(1);
    log("Calling and waiting on function2");
    await function2();
    log(2);

    log("Creating promise3");
    const promise3 = new Promise((resolve, _reject) => {
        log("starting 3000ms timer");
        setTimeout(() => {
            log("fulfilling 3000ms timer");
            resolve();
        }, 3000);
    });
    log("Creating promise4");
    const promise4 = new Promise((resolve, _reject) => {
        log("starting 1000ms timer");
        setTimeout(() => {
            log("fulfilling 1000ms timer");
            resolve();
        }, 1000);
    });
    log("Waiting for promise3");
    await promise3;
    log(3);
    log("Waiting for promise4");
    await promise4;
    log(4);
})();
.as-console-wrapper {
    max-height: 100% !important;
}

With that, we get output something like this:

0000 Calling and waiting on function1
0001 function1 called
0001 starting 3000ms timer
3003 fulfilling 3000ms timer
3004 1
3006 Calling and waiting on function2
3008 function1 called
3009 starting 1000ms timer
4011 fulfilling 1000ms timer
4012 2
4014 Creating promise3
4016 starting 3000ms timer
4017 Creating promise4
4019 starting 1000ms timer
4020 Waiting for promise3
5020 fulfilling 1000ms timer
7018 fulfilling 3000ms timer
7019 3
7021 Waiting for promise4
7023 4

Notice how promise3 and promise4 both start their timers right away, overlapping them.

  • Related