2

I understand the concept of single thread, micro task queue, macro task queue and event loop.

I also know that when an async function is called without the await keyword then the main thread doesn't block waiting for reponse whereas when the async function is called with await keyword then the main thread does block. In both cases the async function is added to task queue.

Today I came across a nested async function example (see code below) where-in the main thread doesn't block in the for loop's 1st iteration even though the function invoked has the await keyword on the nested async function.

It appears that calling an async function, whether nested or not, immediately puts the function into the task queue without checking what code is inside the async fucntion (that is - whether there is await or not)?

In other words - the main thread doesn't enter the child function foo if the parent is not awaited?

Why does the await in the foo not block the for loop where as the await foo.. in the for loop would have blocked the loop?

async function foo(i) {
  await new Promise(resolve => setTimeout(resolve, 5000));
  console.log('Completed', i);
}

for (let i = 0; i < 10; i++) {
  foo(i);
  console.log('Fired', i);
}

console.log('Done firing all async functions, unblocking...');
variable
  • 8,262
  • 9
  • 95
  • 215
  • "*when the async function is called with await keyword then it does block.*" it doesn't *block*. It just acts like synchronous code. However, it does yield to the processing thread until resolved. – VLAZ Feb 17 '22 at 19:11
  • I meant the main thread blocks I will update it. But does it put the async fn into macro or micro task queue? – variable Feb 17 '22 at 19:13
  • "*Today I came across a nested async function example (see code below) where-in the main thread doesn't block in the for loop's 1st iteration*" you already said it: "*I also know that when an async function is called without the await keyword then the code doesn't block waiting for reponse*" - calling `foo()` without `await` will not stop and wait at all, just proceeds. – VLAZ Feb 17 '22 at 19:14
  • Ok this is my first time with a nested async function. I thought js only puts awaited async functions into the task queue. I now realize that the main thread doesn't enter the child fucntion if the parent is not awaited. – variable Feb 17 '22 at 19:16
  • And it does. When the execution of `foo()` reaches `await`, the function is suspended until the awaited expression resolves. However, since `foo()` itself is not awaited, then nothing is preventing the loop from conitnuing. The whole point of async functions is that once you call them, that's done and you can continue. They are going to finish what they do at a later point (asynchronously). *Unless* you use `await` which means "I'm calling this now but I want to continue after it is finished". – VLAZ Feb 17 '22 at 19:18
  • "*In other words - the main thread doesn't enter the child function `foo` if the parent is not awaited.*" No, that is not true. – VLAZ Feb 17 '22 at 19:20
  • What if there was a subsequent await of another fucntion like bar immediately after the un-awaited foo? Will bar have preference over foo? – variable Feb 17 '22 at 19:22
  • Then the resolution can come in any order. Since you're not explicitly waiting for `foo` it could finish before or after `bar()`. Depends on which takes longer. But since `bar()` is awaited, the loop would only continue after it. You might get in terms of resolution order `foo(1)`, `bar(1)`, `foo(2), `bar(2)`, `foo(3)`, `bar(3)` or it could be `bar(1)`, `bar(2)`, `bar(3)`, `foo(1)`, `foo(2), `foo(3)` or even `bar(1)`, `bar(2)`, `foo(2), `bar(3)`, `foo(1)`, `foo(3)` assuming these take a variable amount of time to finish. The `bar` promises will always resolve in order. No guarantee for `foo`s. – VLAZ Feb 17 '22 at 19:27
  • But foo is added to queue first so how can it run (get chance to use the main thread) after bar? – variable Feb 17 '22 at 19:31
  • When it is added back depends on what is awaited. Otherwise if you have one *really slow* promise that will block *every other promise*. Whereas asynchronous shouldn't really be dependent on the order. Unless you opt in with `await` or use the Promise API like `.then()`. `foo(); bar()` can be resolved in any order if not awaited. Depends on when the body of the function itself finishes. It is untethered from synchronous execution outside of it. – VLAZ Feb 17 '22 at 19:35
  • Example of non-sequential resolution: https://jsbin.com/bebemoz/edit?js,console `bar()` is called second but finishes first. – VLAZ Feb 17 '22 at 19:37

0 Answers0