Defined by MDN,

A Promise is a proxy for a value not necessarily known when the promise is created. It allows you to associate handlers with an asynchronous action's eventual success value or failure reason. This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future.

It has three states:

  • pending: initial state, neither fulfilled nor rejected.
  • fulfilled: meaning that the operation completed successfully.
  • rejected: meaning that the operation failed.

Intro

A promise is basically a wrapper around a value that may or may not be known when the object is first instantiated (created), and provides a method for handling a value after it is known (resolved), or when it's unavailable on failure (rejected).

Breakdown

Let's look at some code:

function getCurrentTime(onSuccess, onFail) {
  // Get the current 'global' time from an API using Promise
  return new Promise((resolve, reject) => {
    setTimeout(function() {
      // randomly decide if the date is retrieved or not
      var didSucceed = Math.random() >= 0.5;
      didSucceed ? resolve(new Date()) : reject('Error');
    }, 2000); // delay by 2000, 2 seconds before responding.
  })
}

Here we have a function getCurrentTime that has two callbacks, onSuccess & onFail. Those are faciliated by creating a Promise object with two states (resolve, reject) which it feeds back to the parent by the return.

We use setTimeout and a random generator to flip between resolve and reject for our example.

var didSucceed = Math.random() >= 0.5;

Then we use a one-line if statement to return a success (resolve) or fail (reject) state to the parent function.

didSucceed ? resolve(new Date()) : reject('Error');

Then as we want to simulate an API statement we add a delay of 2 seconds.

setTimeout(function() {
  // ... code ...
}, 2000); // delay by 2000, 2 seconds before responding.

Usage

Now how to use it?

To catch the value on success, we'll use the then() function available on the Promise instance object. The then() function is called with whatever the return value is of the promise itself. For instance, in the example above, the getCurrentTime() function resolves with the currentTime() value (on successful completion) and calls the then() function on the return value (which is another promise) and so on and so forth.

To catch an error that occurs anywhere in the promise chain, we can use the catch() method.

getCurrentTime()
  .then(currentTime => getCurrentTime())
  .then(currentTime => {
    console.log('The current time is: ' + currentTime);
    return true;
  })
  .catch(err => console.log('There was an error:' + err))

.then Breakdown

So when we do,

.then(currentTime => getCurrentTime())

The return value is the current time (onSuccess), that's then passed to the next then() in the chain.

.then(currentTime => {
  console.log('The current time is: ' + currentTime);
  return true;
})

Which takes that value currentTime and prints it to the console.

The important thing to remember is each time we call .then() it operates on the previously returned value in the chain. So if we do something with the previous value the next .then() call will be handed that value, and so on.

fetch() method & React

Moving on, the fetch() method supports Promises so we can wire in a call to a backend API and handle it similarly:

fetch("/api/getuser")
  .then(resp => resp.json())
  .then(resp => {
    const fullname = resp.fullname;
    this.setState({ fullname: fullname })
  })

First we make a call to /api/getuser that returns:

{
  id: "424324234343ffer3",
  fullname: "John Smith"
}

We get the json() response then pass it to the next .then() call, take that json and pull out the fullname into a constant and then using setState() set the value of the fullname local object.

References

Many thanks to these articles, especially Ari Lerner for his great articles linked here under Full Stack React.