Skip to content

Promises

A promise is an object which can be returned synchronously from an asynchronous function (ref).

Promises can be used to avoid callback hell, and they are more and more frequently encountered in modern JavaScript projects.

A Promise is an object with 3 main properties value and 2 hidden arrays onFulfillment and onRejection. Any function in these arrays will automatically be run with value as an argument.

  • .then method is adding function to onFulfillment.
  • .catch method is adding function to onRejection.

Depending on if we face an error or not, different function will be invoked.

Function in the onFulfillment and onRejection array don't go in the regular callback queue, they enter their own microtask queue.

Sample code

1
2
3
4
5
6
7
8
9
const fetchingPosts = new Promise((res, rej) => {
  $.get("/posts")
    .done(posts => res(posts))
    .fail(err => rej(err));
});

fetchingPosts
  .then(posts => console.log(posts))
  .catch(err => console.log(err));

Explanation

When you do an Ajax request the response is not synchronous because you want a resource that takes some time to come. It even may never come if the resource you have requested is unavailable for some reason (404).

To handle that kind of situation, ES2015 has given us promises. Promises can have three different states:

  • Pending
  • Fulfilled
  • Rejected

Let's say we want to use promises to handle an Ajax request to fetch the resource X.

Create the promise

We firstly are going to create a promise. We will use the jQuery get method to do our Ajax request to X.

const xFetcherPromise = new Promise( // Create promise using "new" keyword and store it into a variable
  function(resolve, reject) { // Promise constructor takes a function parameter which has resolve and reject parameters itself
    $.get("X") // Launch the Ajax request
      .done(function(X) { // Once the request is done...
        resolve(X); // ... resolve the promise with the X value as parameter
      })
      .fail(function(error) { // If the request has failed...
        reject(error); // ... reject the promise with the error as parameter
      });
  }
)

As seen in the above sample, the Promise object takes an executor function which takes two parameters resolve and reject. Those parameters are functions which when called are going to move the promise pending state to respectively a fulfilled and rejected state.

The promise is in pending state after instance creation and its executor function is executed immediately. Once one of the function resolve or reject is called in the executor function, the promise will call its associated handlers.

Promise handlers usage

To get the promise result (or error), we must attach to it handlers by doing the following:

1
2
3
4
5
6
7
xFetcherPromise
  .then(function(X) {
    console.log(X);
  })
  .catch(function(err) {
    console.log(err)
  })

If the promise succeeds, resolve is executed and the function passed as .then parameter is executed.

If it fails, reject is executed and the function passed as .catch parameter is executed.

Note : If the promise has already been fulfilled or rejected when a corresponding handler is attached, the handler will be called, so there is no race condition between an asynchronous operation completing and its handlers being attached. (Ref: MDN)

External Resources