Promises, Promises

3 min readMay 30, 2021

Over the past two weeks, the first of our bootcamp journey, we have learned to work with promises in JavaScript. Largely, these promises have been those arising from fetch requests and the subsequent .then’s translating the retrieved data from JSON format. I noticed that we only ever dealt with promises in a linear fashion (i.e., promise → resolution → some action with the retrieved data); sure there was asynchronicity between that chain of events and the rest of the program we were running, but I wondered how one could work with asynchronicity between multiple promises in parallel.

After doing a little digging, I discovered that there are four methods on the built-in Promise object that allow us to juggle multiple promises and condition what happens subsequently on the state of those promises. Those four methods are Promise.all, Promise.any, Promise.allSettled, and Promise.race. I will give a brief overview of what each can be used to do.

First, each method takes as an argument an iterable collection (such as an array) of promises, so here are some promises that we’ll use in our examples:

let promise1 = fetch('https://somepublicapi/objects/1')
.then(resp => resp.json())
//=> A promise that, if successful, should resolve into object1
let promise2 = fetch('https://somepublicapi/objects/2')
.then(resp => resp.json())
//=> A promise that, if successful, should resolve into object2
let promise3 = new Promise((resolve, reject) => {
setTimeout(reject, 1000)
})
//=> A promise that rejects after one second

Promise.all

Promise.all strikes me as being the most likely to be useful of the four methods, allowing us to perform actions that are dependent on the successful resolution of multiple promises. If each promise in the given array successfully fulfills, Promise.all returns a new array of the responses to each of the promises that we can then work with.

With our example promises, if we call Promise.all on the first two promises (which should each return an object from an API), we get an output of an array containing those two objects.

Promise.all([promise1, promise2])
//=> [object1, object2]

However, if we were to include a third promise in that array, one that we know will fail to be fulfilled, Promise.all will not return the results of any of the promises; it will throw an error.

Promise.all([promise1, promise2, promise3])
//=> Error: Uncaught (in promise) undefined

Promise.all is like a gateway that allows forward progress only if all of the necessary (promised) ingredients are realized. I liken it to the && conditional operator; without every single one of the preconditions, it won’t let anything through. In fact, if a single promise fails, Promise.all will throw its error before letting any of the other promises resolve.

Promise.any

If Promise.all is the equivalent of the && operator, then Promise.any is the || operator. Promise.any takes its array of promises and returns the first promise to be successfully fulfilled, if any.

Promise.any([promise1, promise2, promise3])
//=> The object from whichever promise fulfilled fastest

Promise.any will throw an error if none of the promises successfully fulfill.

Promise.any([promise3])
//=> Error: Uncaught (in promise) AggregateError: All promises were rejected

This is entirely speculation on my part (I am, after all, only two weeks into bootcamp), but Promise.any may be useful if we want to include redundancies in our gathering of resources, where we can be assured that if one source of a necessary bit of data fails we can grab it from another instead. It might also make resource gathering more timely if there are highly volatile connection speeds, as it would allow a continuation of a process upon the success of the (in the moment) fastest fulfilled promise.

Promise.allSettled

Promise.allSettled is like the less-discriminating cousin of Promise.all. Like Promise.all, Promise.allSettled returns an array of responses to promises. Unlike its cousin, however, Promise.allSettled returns all responses, whether the promises were fulfilled or rejected, once every promise has resolved. This allows us to see all of the results of a set of promises, and may be useful if we want to perform multiple actions asynchronously that don’t absolutely depend on the success pf each others’ promises.

Promise.allSettled([promise1, promise2, promise3])
//=> [object1, object2, rejected response]

Promise.race

Like the previous method, Promise.race does not care about success or failure, it only cares about resolution. It will return the result of whichever promise becomes settled, in either the fulfilled or rejected state.

Promise.race([promise1, promise2, promise3])
//=> The result of whichever promise resolves first

--

--

No responses yet