DEV Community

Cover image for Async Task inside Loop in Javascript
Bijish O B
Bijish O B

Posted on • Edited on

Async Task inside Loop in Javascript

In a project, I had a situation to perform an asynchronous task inside a loop. I majorly used the map method to do looping tasks.

myIterable.map((item) => {
    //  task 1 - normal
    //  task 2 - async
})
Enter fullscreen mode Exit fullscreen mode

But the map method does not natively support async tasks, when something is made asynchronous inside the map method it returns some 'pending promises'.

[ Promise{ <pending> },... ]

To make the map method asynchronous I wrapped it with the concept of promises.

The logic is split into three code blocks.

In the first block, we have a function named myAsyncIteration which returns a promise. Inside the promise we perform the asynchronous task and we can confirm the completion by resolving the promise by passing someData

const myAsyncIteration = (item) =>
    new Promise(async (resolve, reject) => {
        //  task 1 - normal
        //  task 2 - async
        return resolve(someData)

    })
Enter fullscreen mode Exit fullscreen mode

In the second block, inside myAsyncLoop we map over every instance in myIterable to myAsyncIteration that returns a promise.

If there are 'n' instances inside myIterable then 'n' promises will be returned. This is wrapped with Promise.all which will ensure all the promises are executed and will contain the data which was resolved from the promises.

const myAsyncLoop = async () => {
    return Promise.all(myIterable.map(async (item) =>
        myAsyncIteration(item)

    ))
}
Enter fullscreen mode Exit fullscreen mode

In the third block, we call myAsyncLoop which returns an array of data sent after resolving each promise. It means 'n' number of someData contributes to arrayOfSomeData.

myAsyncLoop().then((arrayOfSomeData) => {
    console.log(arrayOfSomeData)
    // perform the other work

})
Enter fullscreen mode Exit fullscreen mode

In this way, I performed async tasks inside the map method. This is my first blog post, please share your thoughts and if there are any better methods please mention them also.

Thank you.

Top comments (9)

Collapse
 
peerreynders profile image
peerreynders • Edited

we can confirm the completion by resolving the promise by passing someData.

Perhaps I'm misunderstanding something.

An async task should already be or return a promise (thenable) so wrapping it is unnecessary.

It's synchronous tasks that need to be wrapped in a promise with an executor.

This is wrapped with Promise.all which will ensure all the promises are executed.

If you want all to be settled perhaps you should be using Promise.allSettled() instead as the Promise.all() promise will reject on the first rejection.

In the third block, we call myAsyncLoop which returns an array of data sent after resolving each promise.

It returns a promise that will resolve to the array of data (as your later code demonstrates) unless one of them rejects.

Thank you.

OK, that's the happy path.

How are you dealing with potential rejection?

Edge case: Be careful about promises the may never resolve: e.g. browser autoplay policies can lead to promises from play()/resume() that never resolve.

Collapse
 
bijishjs profile image
Bijish O B

Thank you for your detailed valuable feedback. It gave me more insights into issues that would cause due to the improper handling of promises. I will go through the points you mentioned and correct my code. I want to clarify that I wrote the // task 2 - async comment as an abstraction for an awaiting database record existing check operation. I wish you a good day.

Collapse
 
itsfz1 profile image
Fahim Zada

Using map for async tasks here I'm fetching 10 todos from json place holder.

(async () => {
  //creating 10 values of array filled with indexes 
  const promiseList = [...new Array(10).keys()].map(async (_ , index) => {          
  const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${index + 1}`)
  return await response.json()
})
const resolvedList = await Promise.all(promiseList)
console.log(resolvedList)
})()
Enter fullscreen mode Exit fullscreen mode
Collapse
 
bijishjs profile image
Bijish O B

Thank you for the crisp code demonstration. It gave me insights on using inline async function blocks. I want to clarify that I wrote the task 2 - async comment as an abstraction for an awaiting database record existing check operation. I wish you a good day.

Collapse
 
bijishjs profile image
Bijish O B

Thank you for your valuable feedback. I will go through the points you mentioned and correct my code. I want to clarify that I wrote the 'task 2 - async' comment as an abstraction for an awaiting database record existing check operation. I wish you a good day.

Collapse
 
bijishjs profile image
Bijish O B

I want to clarify that I wrote the // task 2 - async comment as an abstraction for an awaiting database record existing check operation.

Collapse
 
devdufutur profile image
Rudy Nappée

No need to declare async function if you never await anything

Collapse
 
bijishjs profile image
Bijish O B

Thank you for your valuable feedback. I want to clarify that I wrote the // task 2 - async comment as an abstraction for an awaiting database record existing check operation. I wish you a good day.

Collapse
 
devdufutur profile image
Rudy Nappée

I mean here :

const myAsyncLoop = async () => {
    return Promise.all(myIterable.map(async (item) =>
        myAsyncIteration(item)

    ))
}
Enter fullscreen mode Exit fullscreen mode

The first async is useless because you return a promise and on the second I think you should await myAsyncIteration(item).