Understanding JavaScript Promises

Hari Sapna Nair
Last Updated: May 13, 2022

Introduction 

Javascript is a synchronous programming language where instructions are blocked until the current task is completed. But there might be cases where we don't want the program execution to wait, like making an API(Application Programming Interface) call to fetch data. In these cases where asynchronous operations have to be performed, we use Callback, Promises, and async-await
 

Before JavaScript promises were introduced, callbacks were used to perform asynchronous operations. But over the years, JavaScript promises replaced callback functions and are now considered the effective method to handle asynchronous operations. 
 

This blog will cover the concept of JavaScript Promises in detail, along with some examples and frequently asked questions.

JavaScript Promises

A JavaScript promise is similar to a promise in real life. When we make a promise in real life, it guarantees that we will do something in the future. A promise has two possible outcomes: it will be kept when the time comes or won't. The same is true for promises in JavaScript. When a JavaScript promise is defined, it will be resolved when the time comes or rejected.

 

JavaScript promises are objects that represent the eventual completion or failure of an asynchronous operation. It is a means of assurance that a particular operation will occur shortly. Though, the promise doesn't need to be fulfilled every time. For example, if there is a network error, the promise won't be fulfilled.

 

A JavaScript Promise object contains both the producing code and calls to the consuming code. Let's have a look at the syntax of JavaScript Promises.
 

Syntax

let promise = new Promise(function (resolve, reject) {
 // Producing code which may take some time

 // Successful
 resolve();

 // Error
 reject();
});

// Consuming code must wait for a fulfilled Promise
promise.then(
 function (value) {
   // Successful
 },
 function (error) {
   // Error 
 }
);

 

When the above code is executed, a result is obtained which calls one of the two callback functions.

How JavaScript Promises Work

The JavaScript Promise object supports two properties: state and result. Let's have a look at them.

State

DescriptionResult
PendingInitial state, i.e., before the promise succeeds or failsundefined
ResolvedCompleted promisea value
RejectedFailed promisean error object

 

For example, if we request some data from the server using a Promise, it will be pending until the data is received. When we receive the data from the server successfully, the promise will be in the resolved state. If we don't receive any data, the promise will be in the rejected state. 

 

If there are multiple requests, after the first promise is resolved or rejected, a new process is attached to it directly. This is called chaining, which will be discussed in the latter part of this blog.

 

Representation of the process of Promises

 

Creating a JavaScript Promise 

Let's create our first JavaScript Promise. To create a Promise object, we make use of a constructor. It takes two parameters, one for the success case(resolve) and the other for the failure case(reject). Then we use the if-else statement to specify what to do in the success and failure case. If the given condition is met, the promise will be resolved. Otherwise, it will be rejected.
 

Code

// Creating a promise
const promise = new Promise((resolve, reject) => {
 let promiseKept = true;
 
 // Promise successful
 if (promiseKept) {
   const yesParty = "Gave friends a party!!!";
   resolve(yesParty);
 }
 
 // Promise failed
 else {
   const noParty = "Didn't give friends a party!!!";
   reject(noParty);
 }
});

Consuming a JavaScript Promise 

Now let's use the promise we have created. If you revisit the image at the beginning of this blog, you'll see two cases: resolved and rejected. If the promise is resolved, the .then() method is called. Else if the promise is rejected, it will jump to the catch( ) method.

 

Code:

// Consuming a promise
const checkIfPartyGiven = () => {
 promise
   // Promise successful
   .then((value) => {
     console.log(value);
   })
   
   // Promise failed
   .catch((err) => {
     console.error(err);
   });
};

 

Let's execute the above code by calling the checkIfPartyGiven() function. 

 

Code:

checkIfPartyGiven();

 

Output:

Gave friends party!!!

 

As the above promise is resolved the following message is obtained.

JavaScript Promise Chaining

If there are multiple asynchronous operations to be done and if we try to use Callbacks for them, we'll find ourselves inside a situation called the Callback hell. This situation is solved using promise chaining.

 

Before going to promise chaining, let's look how a callback hell would look like.

 

Code:

// Callback hell
functionA(function (resultFromA) {
 functionB(
   resultFromA,
   function (resultFromB) {
     functionC(
       resultFromB,
       function (resultFromC) {
         functionD(
           resultFromC,
           function (resultFromD) {
             functionE(
               resultFromD,
               function (resultFromE) {
                 console.log(resultFromE);
               },
               errorCallBack
             );
           },
           errorCallBack
         );
       },
       errorCallBack
     );
   },
   errorCallBack
 );
}, errorCallBack);

 

As you can see, the above code is difficult to read and understand. Also, handling errors in the case of callbacks can be challenging. To overcome this issue, we make use of the promises. 

 

Let's see how the above code would look using promises.

 

Code:

// Promise chaining
functionA()
 .then(function (resultFromA) {
   return functionB(resultFromA);
 })
 .then(function (resultFromB) {
   return functionC(resultFromB);
 })
 .then(function (resultFromC) {
   return functionD(resultFromC);
 })
 .then(function (resultFromD) {
   return functionE(resultFromD);
 })
 .catch(errorCallBack);

 

The code becomes much simplified in promises. This is because we are attaching callbacks rather than passing them. Now the code looks cleaner and easier to understand.

 

"JavaScript promises can save you from the callback hell."

 

Let's now see an example of promise chaining.

 

Code:

// Using promises

// First promise
const firstPromise = () => {
 return new Promise((resolve, reject) => {
   setTimeout(() => {
     const flag = true;
     if (flag) {
       resolve("Hello!!!");
     } else {
       reject("Error");
     }
   }, 1000);
 });
};

// Second promise
const secondPromise = () => {
 return new Promise((resolve, reject) => {
   setTimeout(() => {
     const flag = true;
     if (flag) {
       resolve("Welcome to Coding Ninjas");
     } else {
       reject("Error");
     }
   }, 1000);
 });
};

const greetPromise = () => {
 firstPromise()
   .then((value1) => {
     console.log(value1);
     return secondPromise();
   })
   .then((value2) => {
     console.log(value2);
   })
   .catch((err) => {
     failureCallback();
   });
};

 

The code above shows how multiple callbacks can be chained one after another.
 

 

Output

Promise chaining is used in many scenarios in the real world. For example, it is used to fetch resources from an API. The resources are fetched, and a chain of promises is created to execute when the resource is fetched. 

JavaScript Promises Method

Some of the frequently used promises methods are as follows:-

MethodDescription
all(iterable)It waits for all promises to be resolved or any one of them to be rejected.
allSettled(iterable)It waits until all promises are either resolved or rejected.
any(iterable)It returns the promise value as soon as any one of the promises is fulfilled.
race(iterable)It waits until any one of the promises is rejected or resolved.
reject(reason)It returns a new Promise object that is rejected for the given reason.
resolve(value)It returns a new Promise object that is resolved with the given value.
finally()It returns a promise when a promise is either fulfilled or rejected.

Frequently Asked Questions

  1. What is the difference between Callbacks and JavaScript Promises?

Ans:-  A Callback is a function that is called inside another function. It may or may not be performed asynchronously. A Promise is an object which takes a callback and executes it asynchronously. 
 

2.  What is async-await?

Ans:- async-await is syntactic sugar over JavaScript promises. async makes a function return a JavaScript Promise, and await makes a function wait for a JavaScript Promise.

 

3.  What is meant by synchronous and asynchronous code in JavaScript?

Ans:- The code is synchronous when it blocks further execution of the remaining code until it finishes the current one. In contrast, asynchronous code allows the program to be executed immediately. 

 

4.  Which one is better, promise or callback?

Ans:- A promise is better than a callback as a promise is more readable,  easier to use, and maintain than callbacks.
 

5.  What is meant by a callback hell?

Ans:- The Callback hell/ Pyramid of Doom is when every callback takes an argument resulting from the previous callbacks. Here, the code structure looks like a pyramid, making it difficult to read and debug. If there is an error in one function, then all other functions get affected.

Key Takeaways

This blog covered the basic concepts of Javascript promises, along with some examples and frequently asked questions.

 

Don't stop here. Check out our Basics of JavaScript - guided path to learn JavaScript from scratch. If you are preparing for JavaScript Interviews, check out the blog Javascript Interview Questions.

 

We hope you found this blog useful. Liked the blog? Then feel free to upvote and share it.

Was this article helpful ?
1 upvote

Comments

No comments yet

Be the first to share what you think