Krzysztof Żuraw Blog

You don't know promises

March 02, 2018

Recently I receive book recommendation. There was one chapter in this book series about Promises that I cannot handle. Examples written there were not enough for me - I decided to play with Promises on my own.

Of course, this books is You Don’t Know JS. If you didn’t read it before reading this blog post I encourage you to read those book series. This blog post is an addition to the chapter about promises.

The first example is simple fetch:

fetch('https://httpbin.org/get?name=krzysztof')
  .then(response => response.json())
  .then(json => console.log(json))

It is using fetch to get json response from httpbin. Nothing serious here besides fetching data from external API and unpacking it to JSON.

Promises in the race

The second example is using Promise.race:

const fetchName = name =>
  fetch(`https://httpbin.org/get?name=${name}`)
    .then(response => response.json())
    .then(json => json)

const fetchLastName = lastName =>
  fetch(`https://httpbin.org/get?lastname=${lastName}`)
    .then(response => response.json())
    .then(json => json)

const race = Promise.race([fetchName('krzysztof'), fetchLastName('zuraw')])
race.then(value => console.log(value)).catch(err => console.log(err))

In the beginning, I added functions that allow me to have my code reused. The most important part here is race declaration.

What is Promise.race doing? It waits for first of provided promises to resolve and console.log this value.

I also catch error so if I have my function that I always failing:

const fetchLastNameWithError = lastName =>
  fetch(`https://htpbin.org/get?lastname=${lastName}`)
    .then(response => response.json())
    .then(json => json)

const raceWithError = Promise.race([
  fetchName('krzysztof'),
  fetchLastNameWithError('zuraw'),
])
raceWithError
  .then(value => console.log(value))
  .catch(err => console.log('Error in race: ', err))

I will get Error in race: TypeError: Failed to fetch.

Mega promise

What if I want to get data from two sources and used it later? I can use Promise.all:

const allResults = Promise.all([fetchName('krzysztof'), fetchLastName('zuraw')])

allResults.then(values => {
  const [fetchNameResponse, fetchLastNameResponse] = values
  console.log(
    `My name is ${fetchNameResponse.args.name} ${
      fetchLastNameResponse.args.lastname
    }`
  )
})

It will wait until all promises provided to all call resolve and logs: My name is krzysztof zuraw. Here is a tricky part - what if fetchLastName response comes first before fetchName? As it turns out the order of Promises added to all call is preserved.

Similarly as in Promise.race throwing an error results in stopping at first rejection:

const allResultsWithError = Promise.all([
  fetchName('krzysztof'),
  fetchLastNameWithError('zuraw'),
])
allResultsWithError
  .then(values => {
    const [fetchNameResponse, fetchLastNameResponse] = values
    console.log(
      `My name is ${fetchNameResponse.args.name} ${
        fetchLastNameResponse.args.lastname
      }`
    )
  })
  .catch(err => console.log('Error in all: ', err))

It will log Error in all: TypeError: Failed to fetch.

Summary

Before I end this blog post let me recap what I learned today: Promise.race which will returns a new promise with first resolved value and Promise.all which waits for all promises to be either fullied or rejected.

You can find those examples in this codepen.

Thank you for reading and if you have any comments do not hesitate to write.

Tagged with javascript promises
Want a monthly digest of these blog posts?

I turned off Disqus comments. If you want to give me feedback please write to krzysztofzuraw(at)fastmail.com or use Keybase.


Krzysztof ŻurawDelivered by Krzysztof Żuraw. Opinions are my own. You can follow updates via RSS feed.