Telerik blogs
JavaScriptT2 Light_1200x303

This post covers the necessary fundamentals to having a good understanding of promise. It covers resolve, reject, callbacks and chaining in ECMAScript 6.

The JavaScript promise is a great feature that has helped developers to write clean, elegant code. At the core, a promise is just an object that produces a single value some time in the future. If the promise was fulfilled, it produces a resolved value; on the contrary, it rejects with an error on why if the promise can’t be fulfilled.

Dissecting Promises

In the simplest terms, a promise allows you to run some code asynchronously (without blocking the execution of the rest of your program); depending on the result—whether it failed or succeeded—it then runs other code after it completes. More importantly, it does this in a way that avoids what JS developers have referred to over the years as “callback hell.”

A promise has three states:

  • Pending: This is the initial state of the promise before an operation begins
  • Fulfilled: The request was successful
  • Rejected: The request was unsuccessful

One of the misconceptions people have is that when a promise is settled it has been resolved, but in fact what it means is that the promise has either been resolved or rejected. So before the operation of a promise commences, it’s pending, and after the request begins it gets settled (either fulfilled or rejected).

Note: Once a promise is settled it cannot be resettled. It strictly produces only a single value.

By convention, you cannot access the state of a promise; only the function that creates the promise knows when it’s settled and whether it got resolved or rejected.

Create a Promise

Now, let’s create a simple promise just to set the groundwork.

    const get =  x => new Promise((resolve, reject) => {  
      // condition
    });

Firstly, we created an anonymous function that takes in an argument x and returns a constructor that creates a promise object. The promise object takes two parameters, one for success (resolve) and one for failure (reject):

    if (x % 2 === 0) {
      resolve(`${x} is an even number`);
    } else {
      reject("sorry");
    }

Next, if the condition above is True, the promise will be resolved; else it will be rejected.

To sum it all up, the function returns a promise that resolves if the argument passed is an even number, and it rejects if it’s not. So we have created our first promise. Now let’s use it.

Promise Resolved

    get(3)
    .then(res => {
      console.log(res);
    })

The get function is called with an argument 3, after which the .then method gets called if and only if the promise gets resolved.

Promise Rejected

    .catch(error => {
      console.log(error);
    })

If, based on the condition, the promise gets rejected, the .catch method gets called and it logs the error.

    .finally(() => {
      console.log("Are You Satisfied");
    });

The .finally is called once the promise has been settled (whether it gets resolved or rejected, it gets called after the promise is settled).

Note: I recommend always ending all promise chains with a .catch(), or .finally is needed.

Before Promise: CallBacks

Before the promise feature was added to JavaScript, developers used callback (when a function accepts another function as an argument, this contained function is known as a callback). Don’t get me wrong—callback is still useful. It’s a core functional programming concept still in use in simple functions like setTimeout or making API calls.

    setTimeout(() => {
      console.log("You Can't Get Rid Of Me You See")
    }, 1000)

Later on, developers coined the term “callback hell” because callbacks can get messy if you chain a lot of them together. Let’s see an example:

    request(function(response) {  
        secondRequest(response, function(nextResponse) {    
            thirdRequest(nextResponse, function(finalResponse) {     
                console.log('Final response: ' + finalResponse);    
            }, failureCallback);  
        }, failureCallback);
    }, failureCallback);

You can see how confusing it is to pass each function as a callback. Callback functions are useful for short asynchronous operations, but when working with large sets, this is not considered best practice. So we still use callback functions with promises, but differently (chaining).

Promise Chaining

Because .then() always returns a new promise, it’s possible to chain promises with precise control over how and where errors are handled. Now, let’s handle the same callback operation above with promises—this time the same code looks much cleaner and easier to read:

    request()
      .then(function(response) {
        return secondRequest(response);
    }).then(function(nextResponse) {  
        return thirdRequest(nextResponse);
    }).then( 
    function(finalResponse) {  
        console.log('Final response: ' + finalResponse);
    }).catch(failureCallback);

The above code shows how multiple callbacks can be chained one after another with a synchronous flow of execution. Chaining is one of the best features of promise.

Conclusion

Fully understanding what is covered in this post is crucial to furthering your understanding of promise. I hope you found it helpful.


Chinedu
About the Author

Chinedu Imoh

Chinedu is a tech enthusiast focused on full-stack JavaScript and Infrastructure engineering.

Related Posts

Comments

Comments are disabled in preview mode.