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);
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 */
}
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 */
}
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.
Top comments (0)