Promises, promises
Tags: javascript, promises
Published: 2019-08-14 10:15:25

---
title: Promises, promises
published: true
tags: javascript, promises
canonical_url: https://hellocode.dev/promises
cover_image: https://images.unsplash.com/photo-1531417666976-ed2bdbeb043b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1950&q=80
---

Unlike a lot of other languages, JavaScript is single-threaded which means it can only process one command at a time. We often need to get data from other sources, be it from a database, server or the user and I'm sure you can imagine how bad our applications would be if we had to pause the execution of our program each time we were waiting. Promises solve this problem for us, we request some data from wherever we're getting it from and we set the actions which we want to run once the data is returned. This leaves our single-thread free to carry on with other tasks in the meantime.

Until quite recently it was necessary to use a third-party library for promises (jQuery's _Deferred_ was the most popular) but since ES6 they have been native to JS. Here's the basic pattern:

```js
const promise = new Promise(resolve =>
  setTimeout(() => resolve('I waited for 2 seconds'), 2000)
)

promise.then(message => console.log(message))
// I waited for 2 seconds
```

First we create a new `promise` object from the `Promise` constructor. This takes a function as an argument which is called with a function to execute when you want the promise to be resolved. I have just used a `setTimeout` in this example to keep things simple but you would normally make calls to an API or query a database (in [Node](https://nodejs.org/)) here. After that we can use Promise's `then` method to execute something when the promise is resolved.

## <svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>Error handling

So that's how you use promises... As long as nothing goes wrong! With the above code there isn't anything in place to handle the potential outcome of the API returning an error status. Fortunately, handling errors is pretty straightforward:

```js
const promise = new Promise((resolve, reject) =>
  setTimeout(() => {
    const chaos = Math.random()
    if(chaos > 0.5) {
      reject('Too much chaos!')
    } else {
      resolve('I waited for 2 seconds')
    }
  }, 2000)
)

promise.then(
  message => console.log(message),
  errorMessage => console.error(errorMessage)
)
```

The function called in the `Promise` constructor is actually called with two callback functions; the second being one for rejecting the promise. In much the same way, `then` also accepts a second callback which executes if the promise is rejected.

## <svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>Promise chaining

It is possible to chain `then` functions after a promise. This is also a good place to introduce you to `catch`. When chaining, it is usually the case that you will only use `then` for handling promises, a `catch` can be added to the end of the chain to catch an error thrown from any point preceding it.

Here we will get our promise from another source; I quite often use [Axios](https://github.com/axios/axios) to make HTTP requests. Their API is really simple, to make a GET request you just write `axios.get('api/endpoint/url')` which returns a promise that resolves when the data is returned from the server.

```js
axios.get('api/endpoint/url')
  .then(response =>
    saveData(response)
    axios.get('api/endpoint/url2')
  )
  .then(response2 =>
    saveData(reponse2)
  )
  .catch(error =>
    handleError(error)
  )
```

Here we call our imaginary `saveData` function with the response from the first API call, then make another request to a different endpoint. If an error is thrown anywhere in this chain it will be caught by the `catch` function which passes the error object to another imaginary function - `handleError`.

Promise also has a `finally` method which can be added to the chain, it's pretty handy for spinners!

```js
showSpinner()
axios.get('api/endpoint/url')
  .then(response =>
    saveData(response)
    axios.get('api/endpoint/url2')
  )
  .then(response2 =>
    saveData(reponse2)
  )
  .catch(error =>
    handleError(error)
  )
  .finally(() =>
    hideSpiner()
  )
```

  

## <svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>Async/await

There is now (since ES2017) a cleaner way than chaining `then` functions on a promise. The above could be written using async/await like so:

```js
async function getData() {
  const data1 = await axios.get('api/endpoint/url')
  saveData(data1)
  const data2 = await axios.get('api/endpoint/url2')
  saveData(data2)
}
```

We prepend the `async` keyword to the function declaration and then use `await` anywhere we want to pause execution to wait for a promise to resolve.

Unfortunately, error handling with async/await is not as clean as before and the only way (that I know of) to achieve the same level of error handling as above is to wrap everything in a `try/catch` block:

```js
async function getData() {
  try {
    const data1 = await axios.get('api/endpoint/url')
    saveData(data1)
    const data2 = await axios.get('api/endpoint/url2')
    saveData(data2)
  } catch(error) {
    handleError(error)
  }
}
```

  

## <svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>Asynchronous programming

The examples above work perfectly well but, unless we need to wait for the result of the first call so that we can use the data in the response to make the second call, it is a very inefficient way of programming. I can illustrate this with some code.

First, let's create a mock HTTP GET method:

```js
function get(response, delay) {
  return new Promise(resolve => {
      setTimeout(() => resolve(response), delay * 1000)
  })
}
```

This function just returns the `response` which we set with the first argument after waiting for amount of time set with the second argument, `delay`. We also need to be able to time the test cases we're going to write so let's make a stopwatch:

```js
const stopwatch = (() => {
  let start, end
  return {
    start() {
      start = Date.now()
    },
    stop() {
      end = Date.now()
      return (end - start) / 1000
    }
  }
})()
```

I've used a closure here, if you're not clued up on closures then you should check out my post about them [here](/using-closure). Next, we'll recreate the functions from above:

```js
const testCases = {

  one() {
    return new Promise(resolve => {
      const responses = []
      get('three', 3)
        .then(res => responses.push(res))
        .then(() => get('two', 2))
        .then(res => responses.push(res))
        .then(() => get('one', 1))
        .then(res => responses.push(res))
        .then(() => {
          const output =responses.join(' ')
          resolve(output)
        })
    })
  },

  two() {
    return new Promise(async resolve => {
      const first = await get('three', 3)
      const second = await get('two', 2)
      const third = await get('one', 1)
      const output = `${first} ${second} ${third}`
      resolve(output)
    })
  }
}
```

Hopefully you can recognise the code from earlier, only here we are making three `get` requests instead of two. `testCases.one` pushes all of the data into an array whereas `testCases.two` uses `await` to wait for the promises to resolve before assigning the data to local variables. Notice that we create a `new Promise` and then make the `get` request within which also returns a promise each time. When we have received all of our data we resolve our 'master' promise. So now, all that remains to do is add the code which runs these tests:

```js
async function runTest(testCase) {
  let result, time;
  stopwatch.start()
  result = await testCases[testCase]()
  time = stopwatch.stop()
  console.log('Result: %s, Time: %s seconds', result, time)
}
```

This function is called with the name of the test we want to run, it starts the stopwatch and then runs the test. When the test's promise is resolved the stopwatch is stopped and the results are logged to the console. Let's run our tests:

```js
runTest('one') // Result: three two one, Time: 6.003 seconds
runTest('two') // Result: three two one, Time: 6.004 seconds
```

So you can see that both of our functions took six seconds to run, this is because we have written our code synchronously; each line is executed in order and will wait for the previous lines to complete before running itself. We can instead play to JavaScript's strengths and write our code asynchronously. We'll add a third test to our `testCases` object:

```js
three() {
    return new Promise(resolve => {
    	const responses = []

      function check() {
      	if(responses.length > 2) {
      		resolve(responses.join(' '))
      	}
      }

      get('three', 3).then(res => {
      	responses.push(res)
      	check()
      })
      get('two', 2).then(res => {
      	responses.push(res)
      	check()
      })
      get('one', 1).then(res => {
      	responses.push(res)
      	check()
      })
  	})
  }
```

There's a bit more going on with this function. First we initialise our empty `responses` array, then we've added a function called `check`. Following that we make our three `get` requests as before, only this time we call `check` each time one resolves. `check` looks at the length of our `responses` array and, when our array contains the three responses, it resolves our 'master' promise. Let's see how it does:

```js
runTest('three') // Result: one two three, Time: 3.002 seconds
```

Half the time, and you can see that the order of our responses has changed, our code is running asynchronously!

## <svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>Promise.all()

There is a better way to write test-case number three so that we don't need the `check` function. We can also put our responses back into the same order as the other tests; in the real world this probably isn't important but let's do it anyway!

Time for a confession, I have forgotten to mention something very important about promises. Promises are always in one of three states. When you first create a promise it is in a "pending" state, it is then transitioned into either a "resolved" or "rejected" state. Once a promise has reached "resolved" or "rejected" it cannot go back to "pending". If you want to know which state a promise is in you can call `Promise.state()`, this is pretty useful when debugging as you can set a breakpoint and run this in the console (I might do a post on debugging in Chrome soon).

Here's test-case number four:

```js
four() {
  return new Promise(resolve => {
    const responses = []
    responses.push(get('three', 3))
    responses.push(get('two', 2))
    responses.push(get('one', 1))
    Promise.all(responses)
      .then(values => {
        const output = values.join(' ')
        resolve(output)
      })
  })
}
```

In this function we push the returned promises from the `get` call into the `responses` array straight away. These promises are in a "pending" state and will act as placeholders, meaning that the results will be in the same order as our first two test-cases. Instead of checking the length of the `responses` array each time a promise resolves we can use Promise's `all` method, which itself returns a promise that resolves when all of the promises in the array resolve. This is much better than before because we no longer need to know how many promises we are waiting for:

```js
runTest('four') // Result: three two one, Time: 3.003 seconds
```

Three seconds again and this time the results are in the correct order. Here's the running code from above if you would like to run the tests yourself:

<iframe width="100%" height="300" src="//jsfiddle.net/matthewthorning/95y2bv1k/145/embedded/js,html,css,result/dark/" allowfullscreen="allowfullscreen" allowpaymentrequest frameborder="0"></iframe>
* * *

Hopefully you found this post useful, thanks for taking the time to read to the end. If you have any comments, corrections or questions then you can contact me on Twitter. 👍