Promise Combinators

Scott Beeker
2 min readFeb 2, 2021

Promise combinators explained

Promises added to ECMAScript 2015 specification gave us a new way of dealing with deferred computations. In “From callback hell through promises to async functions” I explained the differences between the common methods of dealing with asynchronous code. Today I would like to go through Promise combinators — static methods that take compound promises as an argument.

promise combinators follow me on twitter Scott Beeker https://twitter.com/beeker_scott

Prerequisite — basic promise states and methods #

The then, catch, finally, resolve and reject methods should already feel comfortable by now but just in case you need a refresher, let’s have a quick glance at this simple example.

fetch("https://api.github.com/users/pawelgrzybek")
.then(data => data.json())
.then(dataJSON => console.log(dataJSON))
.catch(error => console.error(error))
.finally(() => console.log("Finally resolved / rejected! Uff!"));

Promise object like this can live in four distinguished states:

  • “pending” — still waiting
  • “fulfilled” — promise succeeded
  • “rejected” — promise failed
  • “settled” — succeeded or failed

To orchestrate its lifecycle, promises are using a few methods from it’s prototype:

  • then - adds callback to fulfilled promise
  • catch - adds callback to rejected promise
  • finally - adds callback to settled promise

Of course all of these are much more complicated, but to comfortably grasp the concepts explained in the rest of this article this should be more than enough.

Four combinators #

The Promise.all and Promise.race are part of a JavaScript since 2015. In 2020 Promise.allSettled joins the gang. Promise.any is nearly there (TBC).

  • Promise.all - ES 2015
  • Promise.race - ES 2015
  • Promise.allSettled - ES 2020 (proposal)
  • Promise.any - TBC (proposal)

Promise.all() #

Use Promise.all when you want to check whether all promises fulfilled or if one of them rejected.

Promise.all([
fetch("https://api.github.com/users/pawelgrzybek").then(data => data.json()),
fetch("https://api.github.com/users/gabriel403").then(data => data.json())
])
.then(data =>
console.log(`Cool dudes are: ${data.map(dude => dude.name).join(" and ")}`)
)
.catch(error => console.error(error));

Promise.race() #

Use Promise.race when you want to handle the first fulfilled promise or if one of them rejected.

Promise.race([
fetch("https://api.github.com/users/pawelgrzybek").then(data => data.json()),
fetch("https://api.github.com/users/danjordan").then(data => data.json())
])
.then(data => console.log(`The winner is: ${data.name}`))
.catch(error => console.error(error));

Promise.allSettled() #

Use Promise.allSettled when you want to handle when all promises are settled regardless of the result (fulfilled or rejected). Look ma, no catch!

Promise.allSettled([
fetch("https://api.github.com/users/pawelgrzybek").then(data => data.json()),
fetch("https://api.github.com/users/danjordan").then(data => data.json())
])
.then(result => console.log(`All settled`));

Promise.any() #

Use Promise.any when you want to handle the first promise that fulfills. In contrast to Promise.race it doesn’t reject when one of the promises fail.

Promise.any([
fetch("https://api.github.com/users/pawelgrzybek").then(data => data.json()),
fetch("https://api.github.com/users/gabriel403").then(data => data.json())
])
.then(result => console.log(`Cool dude is: ${result.name}`))
.catch(error => console.error(error));

To recapitulate #

Hopefully this article helped you out. This should help pull it all together for you.

promise combinators follow me on twitter Scott Beeker https://twitter.com/beeker_scott

Credits to Paweł Grzybek

--

--

Scott Beeker

Full Stack Developer Learning something new each and every day.