loading...

Sanity Tip For JavaScript Devs: Learn to Run Asynchronous Functions in Array.map()

mjraadi profile image Mohammadjavad Raadi ・2 min read

The Problem

I was writing some API code recently using Node.js, and came across a place where I needed to use Array.map() with an async function on each item. I was briefly surprised when my map call did not work right. Logging the output of the map function would show this:

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

I was expecting to get an array of objects which each would be returned from an asynchronous API call inside the map function, but got this.

Why Use Asynchronous Function Inside Array.map()

Array.map() is a synchronous operation and runs a function on each element in the array resulting in a new array with the updated items. There are situations where you want to run asynchronous functions within map, e.g. updating a list of models and push the changed information back to the database or request information from an API that you want to use for further operations.
Let’s solve the problem of running an asynchronous operation in a synchronous function!

The Solution: Promise.all

An approach to perform async actions in array.map() is to return a promise for each item which then resolve outside the map function. Because map won’t wait for the promise to resolve, it’ll return a pending promise.

You need to take care of all promises in the array returned from map to resolve before using their results. Do this with Promise.all(<array-of-promises>). The result of waiting for all promises to finish is another array containing the results.

Let’s visualize the idea with an example:

const list = [] //...an array filled with values

const functionWithPromise = item => { //a function that returns a promise
  return Promise.resolve('ok')
}

const anAsyncFunction = async item => {
  return await functionWithPromise(item)
}

const getData = async () => {
  return await Promise.all(list.map(item => anAsyncFunction(item)))
}

const data = getData()
console.log(data)

async/await is one of my favorite new features in JavaScript as it makes asynchronous JavaScript code much more readable. If you’re like me, you’ll find Promise.all incredibly helpful while working with async/await.

The main thing to notice is the use of Promise.all(), which resolves when all it’s promises are resolved. list.map() returns a list of promises, so in result we’ll get the value when everything we ran is resolved. Remember, we must wrap any code that calls await in an async function.
I hope this has been helpful to you. Please make sure to leave a comment or any questions you may have down below.

About Me

I am a full stack web developer and co-founder of Bits n Bytes Dev Team, a small group of highly talented and professional freelance developers, where we provide custom web application development services based on cutting-edge technologies, tailored to client's unique business needs.

I'm available for hire and you can check out my portfolio website at https://www.bitsnbytes.ir/portfolio or contact me at raadi@bitsnbytes.ir.

Posted on by:

mjraadi profile

Mohammadjavad Raadi

@mjraadi

Full Stack JavaScript Developer | Building Web Apps | Working With Vue, React, Node.js & MongoDB | Open to Remote Roles

Discussion

markdown guide
 

Why not just use an old-school for-loop? Easy-peasy, problem solved and my promises resolve in the order I call them; unlike Promise.all()...

Genuinely asking.

 

One use case for getting a promise back is if you are uploading a bunch of files and you want to check if any of them failed and do some operation to either auto try that specific one or help the user figure out which one failed.

 

I'm not sure if you're asking why use map over for-loops but if you are, checkout out this post. You can scroll down to the "Benefits of map over for loops" section.
I use Promise.all when the order of my async functions to be resolved is not important but I need them all to be resolved before I can go on.