Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Async/Await work properly when the loop is inside the async function and not the other way around?

I have three snippets that loop three times while awaiting on a promise.

In the first snippet, it works as I expect and the value of i is decremented with each await.

let i = 3;

(async () => {
  while (i) {
    await Promise.resolve();
    console.log(i);
    i--;
  }
})();

Output:

3
2
1

In the second one, the value of i is continuously decremented until it reaches zero and then all the awaits are executed.

let i = 3;

while (i) {
  (async () => {
    await Promise.resolve();
    console.log(i);
  })();
  i--;
}

Output:

0
0
0

Lastly, this one causes an Allocation failed - JavaScript heap out of memory error and doesn't print any values.

let i = 3;
while (i) {
  (async () => {
    await Promise.resolve();
    console.log(i);
    i--;
  })();
}

Can someone explain why they exhibit these different behaviors? Thanks.

like image 433
Ahmed Karaman Avatar asked Mar 24 '19 12:03

Ahmed Karaman


People also ask

Why await only works inside an async function?

async and await are both meta keywords that allow asynchronous code to be written in a way that looks synchronous. An async function tells the compiler ahead of time that the function will be returning a Promise and will not have a value resolved right away. To use await and not block the thread async must be used.

What happens if you use await inside a loop?

You need to place the loop in an async function, then you can use await and the loop stops the iteration until the promise we're awaiting resolves. You could also use while or do.. while or for loops too with this same structure.

How does async await work in event loop?

An async function can contain an await expression, that pauses the execution of the function and waits for the passed Promise's resolution, and then resumes the async function's execution and returns the resolved value. You can think of a Promise in JavaScript as the equivalent of Java's Future or C# 's Task.

How does async await work internally?

The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete. await can only be used inside an async method.


1 Answers

Concerning your second snippet:

Caling an async function without awaiting it's result is called fire and forget. You tell JavaScript that it should start some asynchronous processing, but you do not care when and how it finishes. That's what happens. It loops, fires some asynchronous tasks, when the loop is done they somewhen finish, and will log 0 as the loop already reached its end. If you'd do:

await (async () => {
  await Promise.resolve();
  console.log(i);
})();

it will loop in order.

Concerning your third snippet:

You never decrement i in the loop, therefore the loop runs forever. It would decrement i if the asynchronous tasks where executed somewhen, but that does not happen as the while loop runs crazy and blocks & crashes the browser.

 let i = 3;
 while(i > 0) {
   doStuff();
 }
like image 89
Jonas Wilms Avatar answered Oct 25 '22 11:10

Jonas Wilms