With the release of the ECMAScript 2021 Language Specification came some marked upgrades to the humble promise, and I’m really excited to share four of them with you, beginning with
Promise.all() method takes an iterable (a list) of promises as an input, and returns a single
Promise that resolves to an array of the results of the input promises. This returned promise will resolve when all of the input’s promises have resolved, OR if any of the input promises rejects and throws an error.
This method is especially useful when you have multiple asynchronous tasks that you need to wait on to resolve successfully before moving on to the next step in a program.
My team has used
Promise.all() fairly often in our own codebase when we need to call particular REST endpoints but with different inputs: for instance getting product data for several items by passing the product IDs to the endpoint one at a time, then collecting all the results before moving on to displaying them to the user in the browser.
Since I don’t have an actual API endpoint to query for the example above, I’ve just made each
product object successfully resolve with a different clothing item:
I add all three of those objects to the array
productList, and then I pass that array to the
getProductDetails function. Once the function gets called, the variable
productInfo waits until all three of the products in
productList have resolved successfully before returning them (and logging the products to the console in this case).
If any one of the promises were to fail,
promise.all() would immediately throw an error and exit, so this type of method is good when you need to be certain all your promises fulfilled successfully.
Pretty easy, right? Trust me, this functionality has come in really handy for us when we need to collect lots of asynchronous data, and I’m sure you’ll find it useful too.
Ok, so that’s good when you need all the data to resolve successfully, but what if it doesn’t matter whether the promises resolve or reject — they just need to finish? I’m glad you asked…
What you’re looking for if you just need to know when multiple promises have finished, regardless of their outcome, is
Promise.allSettled(). Once again, this method takes in an array and returns an array of objects that describes the outcome of each promise.
When you have multiple asynchronous tasks that do not depend on each other, this is the type of promise method you could reach for. I used this method when I needed to fire off two independent API calls to generate two separate downloadable reports. Neither promise depended on the other succeeding, they just happened to both be initiated with a single button click by the user. And once both promises had come back (for better or worse), I could then inform the user of any reports available for them to view.
For this code snippet, I pass a list of
report objects to the
generateReports() function. Then, once more, the
reportData variable waits for each promise to resolve or reject before returning the data in a new list.
The big difference is that each input returns an object describing the
status of the promise as well as the
value if the promise is
fulfilled or the
reason if the promise is
rejected. The value (or reason) reflects what value each promise was fulfilled (or rejected) with.
Use cases for this particular promise method probably aren’t as plentiful as they are for
Promise.all() (I imagine normally, we want all asynchronous tasks to succeed, not fail), but in situations such as this, where one asynchronous task doesn’t affect the outcome of another, it can fit the bill.
Now let’s move on to when you just need one promise, any promise, in a list, to resolve. Doesn’t matter which one, you just need one to succeed. Why that’s another new method:
As the name suggests,
Promise.any() takes an iterable of
Promise objects and as soon as one promise fulfills successfully, it returns a single promise that resolves with the value from that promise.
Essentially, the function short-circuits after one promise fulfills and does not wait for any of the others to complete (or fail) before moving on. This method will ignore all rejected promises up until the first promise that fulfills, as well.
whichPromiseWins() takes in a list of promises, and whichever of them fulfills first (in this case it will be
promise2), that value is the only one that will get returned.
I’m honestly not sure what the real-world use case is for
Promise.any(); the authors who proposed this addition give an example of determining which REST endpoint amongst three options is fastest, but personally, I haven’t used it yet. If the situation calls for this sort of thing though, I’m sure you’ll know it.
Right, last new promise method to introduce:
Promise.race() is similar to
Promise.any() in that even though an array of promise objects is passed to
Promise.race(), as soon as any of the promises rejects or fulfills, that single value (or reason) is returned.
Promise.race() doesn’t care whether the promises it’s executing fulfill or reject; whichever promise returns first, is the one that moves forward as a
value or a
reason in the program.
Below are a couple of examples of what this might look like.
The first list of promises passed to the
promiseRaces() function, should result in the
p3 rejection being printed out, as
p3 has the shortest
setTimeout period of all the
Promise objects passed in. This is not a problem for
Promise.race(), it just takes the rejection in the
catch() block of the
promiseRaces() function and logs out the reason.
With the second array of promises passed to
promiseRaces(), the variable
p6 should fulfill first. Once
Promise.race() will short-circuit and return the value of
p6 and the program will continue.
I think that the use cases for this method, like
Promise.any(), are less frequent, but I know they’re out there. And when they are,
Promise.race() will be there to handle it.