DEV Community

Toni-Jan Keith Monserrat
Toni-Jan Keith Monserrat

Posted on • Updated on

A Short introduction on Promise.any

Note: You can see the current stage of this proposal at https://github.com/tc39/proposal-promise-any

Description

Promise.any takes an unspecified number of promises that need to be executed. It returns a promise that is fulfilled by the first promise to resolve successfully and the resulting value is passed back.

If all of them fail, Promise.any throws an exception and executes the reject portion of the promise with a list of all the exceptions.

Project.race can do this right?

Project.race operates similarly, but there is one main difference. If any of the passed in promises return an error, Project.race will reject, regardless of the state of other promises. A resolved promise, even if it executes first, will still result in a reject if any of the included promises return an error.

How do we do it before?

Prior to the introduction of Promise.any the pattern for accomplishing this functionality looked something like this.

const p1 = new Promise(/* ... */);
const p2 = new Promise(/* ... */);
const promises = 2;
const errorList = [];
let result = null;

const thenFn = (r) => {
  if (result) return;
  result = r;
  /* do something with result */
}

const errorHandler = (err) => {
  if (errorList.length !== promises) {
    return errorList.push(err);
  }
  /* handle all errors in errorList */
}

p1.then(thenFn).catch(errorHandler);
p2.then(thenFn).catch(errorHandler);
Enter fullscreen mode Exit fullscreen mode

How can we do it now?

With Promise.any the syntax to accomplish the same thing looks like this. It is similar to using Promise.race or Promise.all.

const p1 = new Promise(/* ... */);
const p2 = new Promise(/* ... */);
const promises = [ p1, p2 ];

Promise.any(promises)
  .then(firstResult => { /* do whatever */ })
  .catch(allErrors => { /* do whatever */ })

// or when using async/await

try {
  const firstResult = await Promise.any(promises);
  /* do whatever */
} catch (allErrors) {
  /* do whatever */
}
Enter fullscreen mode Exit fullscreen mode

In what situation would we want to use this?

Let's say you want to fetch several sources of data, including data coming from Cache API. The goal is to retrieve the data as quickly as possible, but you don't need to retrieve it more than once.

try {
  const url = 'https://example.com/api/v1/some-endpoint/data';
  const data = await Promise.any([
    fetch(url),
    fetch('https://example.com/api/v1/some-endpoint-that-hopefully-is-near/data'),
    cache.match(url)
  ]);

  /* render back to browser */
} catch (errors) {
  /* render all error or a general error  */
}
Enter fullscreen mode Exit fullscreen mode

Shoutout

Shoutout to laurieontech for being the 2nd pair of eyes for this article, as well as the JS outreach group for giving me this opportunity.

References

Top comments (0)