Use async / await with Javascript's .map() and other high-order functions
Tags: javascript, todayilearned, webdev
Published: 2021-05-31 19:35:31

TL:DR - Asynchronous, high order array-functions return an array of promises. In order to resolve each of these, you can use one of the following methods:

*   `Promise.all([ /* ... array of promises ... */ ])`  
    Wait for all promises to be resolved, throws errors
*   `Promise.allSettled([/* ... array or promises ...*/ ])`  
    Wait for all promises to be resolved or rejected, requires manual error handling

A variable assignation using `.map()` then looks something like this:

```javascript
const promiseArray = iterableArray.map(async (element) => {
  // ... async code 
  return result;  
});

const dataArray = Promise.all(promiseArray);
```

A simple use case
-----------------

While high order functions have lots of perks, I recently noticed they were not natively capable of handling promises' syntactic sugar very well.

I noticed this problem when developing on serverside Node.js code, which was meant to accept an array of files from an incoming client as formdata and save it to a database. Instead of returning the response I'd expect, namely an array with values, the below function returned me an array of `Promises`:

*   First, the npm [Formidable](https://www.npmjs.com/package/formidable) library would handle form parsing and give me a `files` - object. It would be available only inside the callback's scope.
*   Inside `files`, the first property would indicate the file - array:  
    `const filePropertyName = Object.keys(files)[0]`
*   Having identified these two, I could now iterate through the array of files.
*   For each file, I would then prepare a payload and call an SQL - stored procedure to asynchronously write this file into the database, using [mssql](https://www.npmjs.com/package/mssql).
*   Each successfully performed stored procedure would return me a fileId that uniquely identifies each uploaded file. I would store it in `fileIds` (see code below) and then send the array back to the client.

So far so good, right? Everything that comes after cannot be much harder. Here's the code:

```javascript
// Iterate through the array of files identified by its form property
// ('name' of the client's form field)
const fileIds = files[filePropertyName].map(async (file /* object */) => {

  // Use a private function to create a payload for stored procedure
  // (In order to work, it required some intel from other formfields)
  const payload = this._handleSetUploadPayload(fields,file);
  
  // Create a new FileModel 
  const File = new FileModel(storedProcedureName);
  
  // Use its uploadFile method to trigger the stored procedure
  return await File.uploadFile(payload);
});
```

Well, not so fast. After sending three files down the API, what `fileIds` contained was not exactly what I've been looking for. When I started to debug, I saw the following result:

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

I was puzzled for a moment. And frustrated. [So I started searching MDN and found an explanation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#polyfill) (step 9: `return A`).

The solution
------------

In my own words, that'll be:

> The `.map()` algorithm applies an async callback to each element of an array, creating promises as it does. However, the returned result  by `.map()` is no promise, but an **array of promises.**

That was an answer I could live with. So I changed the code accordingly, primarily by adding `Promise.all()` and - voila, it started to work:

```javascript
const fileIdsPromises = files[filePropertyName].map(async (file) => {
  const payload = this._handleSetUploadPayload(fields,file);
  const File = new FileModel(storedProcedureName);

  const fileId = await File.uploadFile(payload);
  return fileId
});

const fileIds = await Promise.all(fileIdsPromises);
```
> This post was originally published at https://blog.q-bit.me/use-async-await-with-high-order-functions/
Thank you for reading. If you enjoyed this article, let's stay in touch on Twitter 🐤 [@qbitme](https://twitter.com/qbitme)