Working With JavaScript Promises

1. Introduction to JavaScript Promise


JavaScript Promises are one way to deal with asynchronous code in JavaScript, without writing too many callbacks in your code. They are around for years, they were standardized and introduced in ES2015, and now they have been superseded in ES2017 by async functions.

A promise is a method that eventually produces a value. It can be considered as the asynchronous counterpart of a getter function. It can be explained as:

promise.then(function(someValue) {
  // Do something with the 'someValue'
});

Promises can replace the asynchronous use of callbacks, and they provide several benefits over them. They start to gain ground as more and more libraries and frameworks embrace them as their primary way to handle asynchronicity. Ember.js is a great example of such a framework.

There are several libraries that implement the Promises/A+ specification. Here we’ll learn the basics, and work through a few JavaScript promises examples to introduce the concepts behind them in a practical way.

2. How do JavaScript Promises work?


A promise is an object which can be returned synchronously from an asynchronous function. It will be in one of 3 possible states:

  • Fulfilled: onFulfilled() will be called (e.g., resolve() was called)
  • Rejected: onRejected() will be called (e.g., reject() was called)
  • Pending: not yet fulfilled or rejected

A promise is settled if it’s not pending (it has been resolved or rejected). Sometimes people use resolved and settled to mean the same thing: not pending.

Once settled, a promise can not be resettled. Calling resolve() or reject() again will have no effect. The immutability of a settled promise is an important feature.

Native JavaScript promises don’t expose promise states. Instead, you’re expected to treat the promise as a black box. Only the function responsible for creating the promise will have knowledge of the promise status, or access to resolve or reject.

Here is a function that returns a promise which will resolve after a specified time delay:

const wait = time => new Promise((resolve) => setTimeout(resolve, time));

wait(3000).then(() => console.log('Hello Coders!')); // 'Hello Coders!'

3. Creating a JavaScript Promises


The Promise API exposes a Promise constructor, which you initialize using new Promise():

let isDone = true;

const learnJavaScript = new Promise(function (resolve, reject) {
    if (isDone) {
        resolve("I'm have completed my JS learning.");
    } else {
        reject("I haven't completed learning JS yet.");
    }
});

As you can see the promise checks the isDone a global variable, and if that’s true, we return a resolved promise, otherwise a rejected promise.

Using resolve and reject we can communicate back a value, in the above case we just return a string, but it could be an object as well.

4. Consuming a JavaScript Promises


In the last section, we introduced how a promise is created. Now let’s see how the promise can be consumed or used.

const learnJavaScript = new Promise(function (resolve, reject) {
    if (isDone) {
        resolve("I'm have completed my JS learning.");
    } else {
        reject("I haven't completed learning JS yet.");
    }
});

const checkIfJSLearningDone = () => {
  learnJavaScript
    .then(ok => {
      console.log(ok)
    })
    .catch(err => {
      console.error(err)
    })
}

Running checkIfJSLearningDone() will execute the learnJavaScript() promise and will wait for it to resolve, using the then callback, and if there is an error, it will handle it in the catch callback.