1

can someone please suggest a proper way on how I can do asynchronous call simultaneously with the values I extracted from an array?

Currently, I have the below implementation but it looks like a blocking code because of the await which basically waits for the result of the API call before it proceeds with the next iteration.

Your suggestions would be much appreciated. Thanks in advance! :)

async function getDetailsById(){
    let idArr = ['1000', '1001', '1002', '1003'];
    let detailsArray = [];
    for(let i = 0; i < idArr.length; i++){
        let id = idArr[i];
        let details = await callSomeApi(id);
        detailsArray.push(details);
    }
   return detailsArray;
}
jrmtmys
  • 33
  • 4
  • 4
    Possible duplicate of [Using async/await with a forEach loop](https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop) – Liam Mar 07 '19 at 09:04
  • I'd agree with Liam. This is a duplicate and the link he's provided is a good one around using promises. It might be worth stepping away from your actual problem and look at async, promises and promise.all before returning to your problem. – Chris Adams Mar 07 '19 at 09:10
  • 1
    Basically, if you just want to run all the async requests in parallel and then await them all, you could do something like this: `return await Promise.all(idArr.map(id => callSomeApi(id)))` – noseratio Mar 07 '19 at 09:16
  • 1
    @noseratio, your simple solution worked for me! Thank you very much! :) – jrmtmys Mar 15 '19 at 06:16

1 Answers1

-1

You could start all the Tasks and then await Task.WhenAll(...);

I don't know how to do it in your language, but you'll get the gist:

List<Task<returnType>> tasks = new List<Task<returnType>>();
// start all tasks, don't await for the result yet
for (int i=0; i<idArr.Length; ++i)
{
    Task task = callSomeApi(idArr[i]);
    tasks.Add(task);
}

// wait until all tasks finished:
await Task.Wait(tasks);

// if desired use Task.Result to use the return value:
foreach(Task<returnType> task in tasks)
{
    var result = task.Result;
    ProcessResult(result);
}

If you don't want to wait for all tasks to finish, but want to process the result as soon as one of the tasks is finished, use Task.WhenAny, and remove the finished task from the collection of awaited tasks. Use a HashSet for fast removal

HashSet<Task<returnType>> tasks = new HashSet<Task<returnType>>();
// start all tasks, don't await for the result:
for (int i=0; i<idArr.Length; ++i)
{
    Task<returnType> task = callSomeApi(idArr[i]);
    tasks.Add(task);
}

// as long as there are tasks in the HashSet, 
// await until any of the tasks in the HashSet is finished:
while(tasks.Any())
{
    Task finishedTask = await Task.WhenAny(tasks);
    tasks.Remove(finishedTask);
    ProcessResult(finishedTask.Result); // only if there is a result
}
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
  • Apparently someone doesn't like this answer and downvoted me. Couldn't he just write as a comment what is wrong? If it is because it is not in VB: in future someone might have the same problem in C#. Shall I just delete this answer? – Harald Coppoolse Mar 12 '19 at 15:09