# I misunderstood Promise.all in JavaScript

# My misunderstanding of Promise.all

For a long time I thought `Promise.all` was used to fire and run promises concurrently.

Every time I encountered code that used two `await`s, I always proposed using `Promise.all` instead. Now, this still holds true, but I've finally understood how things actually work.

Let's look at some code and later I'll show an example where we combined `Promise.allSettled` with `Promise.all` to enhance the logging.

```javascript
const firstPromise = await someFunction();
const secondPromise = await someOtherFunction();
```

Here `await` makes sure that we wait for the promises to resolve before moving on to the next line. This can be a bit fishy, because `await` actually is syntatic sugar.

Under the hood, this might be translated to something like this:

```javascript
someFunction().then((result) => {
  someOtherFunction().then((result2) => {
    // ...
  });
});
```

# Promise.all

```javascript
const [firstPromise, secondPromise] = await Promise.all([
  someFunction(),
  someOtherFunction(),
]);
```

When we call an async function, it returns a promise. `someFunction()` returns a promise, `someOtherFunction()` returns a promise. These functions are called. The promise runs. First it goes to the Web API environment and then when done moves into the microtask queue.

`Promise.all` says "Let me look at all these promises. When all of them are successfully done, I will return them in an array to you."

That's all it does. It helps us wait for multiple promises to resolve.

## Calling promises again

```javascript
const [firstPromise, secondPromise] = await Promise.all([
  someFunction(),
  someOtherFunction(),
]);

const [firstPromise2, secondPromise2] = await Promise.all([
  someFunction(),
  someOtherFunction(),
]);
```

Here, because we call `someFunction()` and `someOtherFunction()` in both `Promise.all`, we would be firing the promises again. To keep it simple: Every time you call an async function, you create a new promise.

```javascript
someFunction();
someFunction();
someFunction();
```

Here we call `someFunction()` three times. We create three promises that run concurrently. Promises by nature run concurrently. They go into the Web API environment and when done move into the microtask queue.

You might find it confusing that we can just call promises if you're so used to `await`. But to be clear, `.then` or `await` is what we use to "wait" for the result of a promise.

## Using the same promise

```javascript
const firstPromise = await someFunction();
const secondPromise = await someOtherFunction();

const [
  firstPromiseResultFromSomeFunction,
  secondPromiseResultFromSomeOtherFunction,
] = await Promise.all([firstPromise, secondPromise]);

const [
  firstPromiseResultFromSomeFunction2,
  secondPromiseResultFromSomeOtherFunction2,
] = await Promise.all([firstPromise, secondPromise]);
```

Believe it or not, this is fine. We use the same promises in both `Promise.all` calls. Again, all `Promise.all` does is observe the promises and wait for them to resolve. It doesn't create new promises. To emphasize, this code is fine. There are not issues with it besides a bit of duplication.

# Promise.allSettled with Promise.all

This is a pattern I learned from my last startup. We would combine `Promise.allSettled` with `Promise.all`. The problem with `Promise.all` is that as soon as one promise rejects, the entire `Promise.all` call will reject. This is why we use `Promise.allSettled`.

Instead of debugging, fixing one promise, just to realize that another promise is the one that's rejecting, we can use `Promise.allSettled` to get all information we need and guarantee that there are no issues the next time we run the code.

Typically, the code would look something like inside a function:

```javascript
const operations = [
  { name: "fetchUserInfo", promise: fetchUserInfo() },
  { name: "fetchPreferences", promise: fetchUserPreferences() },
  { name: "calculateMetrics", promise: calculateMetrics() },
];

// results looks like -> [{status: 'fulfilled', value: ...}, {status: 'fulfilled', value: ...}, {status: 'rejected', reason: ...}]
const results = await Promise.allSettled(operations.map((op) => op.promise));

results.forEach((result, index) => {
  if (result.status === "rejected") {
    // logger -> e.g. datadog, sentry, etc
    logger.error({
      // operation -> e.g. fetchUserInfo
      operation: operations[index].name,
      // error -> e.g. Error: Failed to fetch user info
      error: result.reason,

      // You can include more fields here if you need
      // ...
    });
  }
});

return await Promise.all(operations.map((op) => op.promise));
```

Some code will be duplicated. You can extract some of it to clean it up.

```javascript
function handleAllSettledResults({ operations, results }) {
  results.forEach((result, index) => {
    if (result.status === "rejected") {
      logger.error({
        operation: operations[index].name,
        error: result.reason,
      });
    }
  });
}
```
