Promises have been around for a while but with ES6 also came its native implementation which we will now have a look at.

So what is a promise anyway? As defined by MDN, the Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value. This means that instead of creating a callback hell for asynchronous requests we can now make use of promises to deal with asynchronous nature of JavaScript.

Promise states

A promise can be in either one of three states:

  • Pending: waiting for operation to finish;
  • Fulfilled: operation finished successfully;
  • Rejected: operation failed.

By default, a promise exists in a pending state. It waits for some operation such as an HTTP request to finish. After the operation finishes successfully, it resolves and transitions into fulfilled state. Otherwise, the promise enters rejected state.

When promise enters fulfilled state, it also executes then method chained onto the promise. Alternatively, if a promise enters rejected state, it will execute the queued up catch method.

Syntax

To create a new promise we simply have to declare a new Promise instance that accepts an executor function which itself takes two parameters, resolve and reject. The full syntax looks as follows:

new Promise((resolve, reject) => { ... });

Now, whenever we want to resolve a promise, all we have to do is call resolve function with the data we want to pass to it. Same with reject in case an error has occurred.

Let's look at an example. Below we can see the most simple promise we can write. It simply resolves as soon as it initiates with a string passed as a data argument. Notice how we first initiate the promise instance with new Promise and then chain then method to resolve the promise value.

const promise = new Promise((resolve, reject) => {
  resolve('finally finished');
});

promise
  .then(res => console.log(res)); // finally finished

Let's do a similar example but now let's reject the promise. This time catch method will get executed and then will be skipped.

const promise = new Promise((resolve, reject) => {
  reject('something went wrong');
});

promise
  .then(res => console.log(res))
  .catch(err => console.log(err)); // something went wrong

Interestingly, since then methods return a Promise in itself, we can chain then methods passing data from one to another. This allows for some neat data manipulation where we iteratively manipulate data to achieve the final form we want to see it in. In the below example we JSONify the string we get passed as part of promise resolve value and then console.log it.

const promise = new Promise((resolve, reject) => {
  resolve('{"name":"John","age":"42"}');
});

promise
  .then(res => JSON.parse(res))
  .then(json => console.log(json)) // { name: 'John', age: '42' }
  .catch(err => console.log(err));

Full example

To see all that we learnt about promises in its entirety let's create the most useless promise ever created. It will randomly resolve or reject after 1 second of waiting and pass random number as its resolved value.

const promise = new Promise((resolve, reject) => {
  const number = Math.random();

  setTimeout(() => {
    if (number < 0.5) {
      reject(new Error('Number is below 0.5'));
    } else {
      resolve(number);
    }
  }, 1000);
});

promise
    .then(res => console.log(res))
    .catch(err => console.log(err));

Notice how setTimeout takes 1 second to call either resolve or reject. This is the type of asynchronous request that promise let's us handle in a much more elegant manner. Otherwise, we would have to resort to callbacks 😵

Fetching API requests

One addition of ES6 that goes like bread and butter with Promises is Fetch API. fetch() takes path as its first argument and it returns a Promise that resolves the response.

fetch('https://jsonplaceholder.typicode.com/posts/1')
  .then(res => res.json())
  .then(json => console.log(json))

Above is a very simple example where we fetch data from a sample API but I hope it gives you ideas of how to use this Fetch and Promise combo for more succint JavaScript code.

Summary

As we have seen, Promises are a great way to handle asynchronous requests and avoid callback hell. They can also be chained via several then methods which allows for neat resolved value manipulation. Finally, promises go like bread and butter with Fetch API so investigate that to make your JavaScript code even more awesome!