# Add safer variants of \`Promise.all\`/\`Promise.race\`

**URL:** <https://es.discourse.group/t/add-safer-variants-of-promise-all-promise-race/1350>\
**Category:** 💡 Ideas\
**Tags:** proposal\
**Created:** [May 21, 2022, 3:19am UTC](https://es.discourse.group/t/add-safer-variants-of-promise-all-promise-race/1350 "2022-05-21T03:19:05Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![claudiameadows](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/claudiameadows/32/126_2.png) [@claudiameadows](https://es.discourse.group/u/claudiameadows)\
**Post date:** [May 21, 2022, 3:19am UTC](https://es.discourse.group/t/add-safer-variants-of-promise-all-promise-race/1350/1 "2022-05-21T03:19:05Z")

</div>

`Promise.all` is the largest source of swallowed rejections in my experience. `Promise.race` has similar issues, but `Promise.any` provided the ability to work around that by returning `AggregateError`s. This is nice, but even on success it might be desirable to track returned errors.

Instead, I'd like to see the following:

1. A variant of `Promise.all` that allows cancelling outstanding tasks if any error occurs, additionally aggregating and propagating those as needed.
2. A variant of `Promise.race` that allows cancelling outstanding tasks upon first success, aggregating errors as needed and returning them alongside the return value.

It'd also be helpful for those to work together with [GitHub - tc39/proposal-explicit-resource-management: ECMAScript Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management), though that's not a requirement.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [May 21, 2022, 3:30am UTC](https://es.discourse.group/t/add-safer-variants-of-promise-all-promise-race/1350/2 "2022-05-21T03:30:35Z")

</div>

Promises aren’t Tasks though - by the time you have a promise, the work - the task - has already begun, and its means of control is separate.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [May 21, 2022, 6:10am UTC](https://es.discourse.group/t/add-safer-variants-of-promise-all-promise-race/1350/3 "2022-05-21T06:10:59Z")

</div>

I assume your variant Promise.all()/Promise.reject() functions would still return promises that settle the same way the original functions do, e.g. the variant Promise.all() would still reject as soon as one promise in the array rejects. The main difference here is that you're additionally able to somehow attach event listeners to the promise collection, so you can be notified of other unhandled rejections.

So, perhaps something like this?

```javascript
const results = Promise.all([
  task1(),
  task2(),
  task3(),
], {
  onRejects: (aggregateError) => log(aggregateError),
});

```

I view the promise-bundling helpers, like Promise.all(), Promise.race(), etc, as ways to get notified when an interesting event happens with a group of promises. Normally you'll just use one of these promise-bundlers (like Promise.all()), but you might sometimes use multiple promise-bundler functions against the same collection if you needed to be notified of different events (e.g. you might use both Promise.race() and Promise.all() against the same collection).

With this in mind, I feel like the idea of giving a function like Promise.all() an additional event-listener parameter feels icky and wrong. Perhaps a more correct solution would be to simply create a new promise-bundler, which I'll call Promise.allRejects(). If someone needs to listen for both Promise.all() and Promise.allRejects() against the same collection of promises, they can do so.

In practice, this would look like this:

```javascript
const promises = [
  task1(),
  task2(),
  task3(),
];

Promise.allRejects(promises).catch(aggregateError => log(aggregateError));

const result = await Promise.all(promises);

```

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [May 21, 2022, 4:25pm UTC](https://es.discourse.group/t/add-safer-variants-of-promise-all-promise-race/1350/4 "2022-05-21T16:25:55Z")

</div>

I have written a `PromiseAllOrErrors` helper that doesn't short circuit on error, so basically waits for settlement of all promises before itself settling.

The question is how to handle cases where short circuiting is actually needed, either in the error path (Promise.all) or either path (Promise.race).

Often the main flow has completed by that point and there is nowhere for a late rejection to be reported. If there were, the program could do both the short circuiting call (all/race) and the non-short-circuiting one (allOrErrors) on the same set of promises, and flow the non-short-circuiting settlement of all promises into that place. This is where @theScottyJam ends up at above.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [May 21, 2022, 4:32pm UTC](https://es.discourse.group/t/add-safer-variants-of-promise-all-promise-race/1350/5 "2022-05-21T16:32:47Z")

</div>

Isn’t that helper just Promise.allSettled?

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [May 21, 2022, 4:36pm UTC](https://es.discourse.group/t/add-safer-variants-of-promise-all-promise-race/1350/6 "2022-05-21T16:36:08Z")

</div>

More or less, it behaves like Promise.all and rejects with an AggregateError in the case of multiple rejections.

Promise.allSettled always fulfills with the settlement result, so it can't be chained like other promises.
