How to create Promises and handle Promise chains in JavaScript
Tags: beginners, codenewbie, webdev, javascript
Published: 2021-02-23 13:08:09

In this tutorial you’ll learn how to **create JavaScript Promises**, how to **handle promise chains** and utilize the functions **Promise.all** and **Promise.race**.

If you're new to the topic you can start with learning about [How asynchronous programming and Promises work in JS](https://learn.coderslang.com/0027-javascript-asynchronous-programming-and-promises/)

## How to create a Promise in JavaScript

A Promise (and a couple of other things) can be created using the `new` keyword:

```javascript
const promise = new Promise(executor);
```

The `executor` argument is a function that has two parameters (also functions):

- `resolve` - used when everything went well and need to return the result
- `reject` - used if an error occurred

The `executor` function is called automatically, however, we need to call `resolve` or `reject` inside of it ourselves.

Let's write a `coinflip` function that simulates a coin toss. It accepts a bet and in half of the cases it ends with an error, and in half of the cases it "thinks" for 2 seconds and returns the doubled bet.

```javascript
const coinflip = (bet) => new Promise((resolve, reject) => {
  const hasWon = Math.random() > 0.5;
  if (hasWon) {
    setTimeout(() => {
      resolve(bet * 2);
    }, 2000);
  } else {
    reject(new Error("You lost...")); // same as -> throw new Error ("You lost ...");
  }
});
```

In the resolve function, we pass a value that will become available after the promise is fulfilled.

And in `reject` - we throw an error. Technically we can use `throw` instead of  `reject`. There will be no difference.

Let's use our `coinflip`.

```javascript
coinflip(10)
  .then(result => {
    console.log(`CONGRATULATIONS! YOU'VE WON ${result}!`);
  })
  .catch(e => {
    console.log(e.message);  // displays the error message if the promise is rejected
                             // in our case: "You lost..."
  })
```

As previously, if everything goes well, we will get the result inside `then`. And we will handle errors inside `catch`.

## JavaScript Promise Chains handling

There are often situations where one asynchronous function should be executed after another asynchronous function.

For example, we can try to bet again if we managed to win a `coinflip`. And then once again.

To do this, you can create **promise chains**. In general, they look like this:

```javascript
promise
  .then(...)
  .then(...)
  .then(...)
  .catch(...)
```

The first `.then` will return a promise, and another `.then` can be attached to it, and so on.

Despite having multiple `.then` blocks, a single `.catch` will suffice, if placed at the very end of the chain. 
Let's add a little refactoring to avoid code duplication and try to win more coins.

```javascript
const betAgain = (result) => {
  console.log(`CONGRATULATIONS! YOU'VE WON ${result}!`);
  console.log(`LET'S BET AGAIN!`);
  return coinflip(result);
};

const handleRejection = (e) => {
  console.log(e.message);
};

coinflip(10)
  .then(betAgain)
  .then(betAgain)
  .then(betAgain)
  .then(result => {
    console.log(`OMG, WE DID THIS! TIME TO TAKE ${result} HOME!`);
  })
  .catch(handleRejection);
```

The betAgain function takes a number, displays the congrats message, and calls `coinflip` again. Then we add as many `.then` blocks as we need to complete the task.

In fact, we only needed `betAgain` to display the debug messages. If we were just interested in the end result, then we could simply pass the `coinflip` function to `.then`. Like this:

```javascript
coinflip(10)
  .then(coinflip)
  .then(coinflip)
  .then(coinflip)
  .then(result => {
    console.log(`OMG, WE DID THIS! TIME TO TAKE ${result} HOME!`);
  })
  .catch(handleRejection);
```

## `Promise.all`, waiting for all Promises to resolve

Let's return from our virtual casino to the real world.

Imagine we have a function `getUserData` that returns the user's name, their `id`, and a list of their friends. Something like this:

```javascript
{
  id: 125,
  name: 'Jack Jones',
  friends: [1, 23, 87, 120]
}
```

We receive it, of course, not immediately, but after the promise becomes `fulfilled`.

And we were given the task of displaying a list of all the user's friends, but not just `id`, but all their data.

We already know how to work with one promise, let's start by displaying a list of `id` friends on the screen:

```javascript
getUserData(userId).then(console.log);
```

Next, we could try to take the list of friends and transform it with `map` so that we have information about each friend:

```javascript
getUserData(userId)
  .then(userData => {
    return userData.friends.map(getUserData);
  })
  .then(console.log)
  .catch(e => console.log(e.message));	
```

Not bad. But on the screen, we will see `[Promise {<pending>}, Promise {<pending>}]` instead of full information about friends.

Unfortunately, we will not be able to add another `then` or `map` here, because we already have an array, and the promises inside of it are still in the `pending` state.

To solve this problem, we need the `Promise.all(array)` function. It takes an array of promises and returns a single promise.

This promise will become `fulfilled` when all the promises from `array` are resolved. And if at least one of them is rejected, then the whole `Promise.all` will be rejected.

```javascript
getUserData(userId)
   .then(userData => {
     return Promise.all(userData.friends.map(getUserData));
   })
   .then(console.log)
   .catch(e => console.log(e.message));
```

Now the program works as expected and we display a list of all the user's friends.

## `Promise.race`, waiting for the fastest promise

If we only need to get the result of the fastest Promise, then we can use the function `Promise.race(arr)`.

Just like `Promise.all`, it takes an array of Promises and returns a single Promise. But you cannot predict in advance the return value after it enters the `fulfilled` state.

`Promise.race` resolves with the value of the fastest Promise of the array.

```javascript
const fastPromise = new Promise((resolve, reject) => {
  setTimeout(() => resolve(`fast`), 100);
});

const slowPromise = new Promise((resolve, reject) => {
  setTimeout(() => resolve(`slow`), 200);
});

const arr = [fastPromise, slowPromise];

Promise.race(arr).then(console.log); // fast
```

In this example, the message `fast` will be displayed on the screen in 100 milliseconds and we will not wait for the second promise to be resolved.

[Learn Full Stack JavaScript](https://js.coderslang.com)