Mastering JavaScript Promises in Under 5 Minutes

In this blog, we are going to learn about promises and how we can handle promises to use asynchronous operations. But before that, we will see an example of how we were doing code before we had promised in javascript and what sort of problems it was creating.

Let's take the example where we are building an e-commerce app shopping cart where we have some items in the cart and to complete the order we need two apis first one is created order () and the second one is processedToPayment() and we need to understand here that we can call processedToPayment() only after creating order () as its dependence on it. Let's see how we used to write this code before we had promised.

let cart = ["shirts","paints","kurta"];

api.createOrder(cart,function processedToPayment(){
  api.processedToPayment();
})

Now we can see in the above code snippet how we are passing the processedToPayement function inside createOrder() and this way processedToPayment() function is dependent on the createOrder() function what if createOrder() function calls this processedToPayment() function twice or what if it never calls the processedToPayment() function so as developer we don't have guarantee what's going to happen with processedToPayment and which is the big issue and this is also known as Inversion on control. Now we understood the problem but let's see how promises can help us to solve this problem.

Now because we have promises in javascript we will build our apis in such a way that they don't need to accept the function as an argument rather they will just take cart details and will return a promise.

let cart = ["shirts","paints","kurta"];

// Only cart details passed no any callback function
const promise = api.createOrder(cart);  // line 2

In the above code snippet, we have just passed cart details in the createOrder() API and it is just returning the promise. And this promise is nothing but just an empty object for a time being so this create order() is an asynchronous operation and it may take some time to get finished till that time the promise will have no data but as soon as create order () has response then that will be passed into the promise and we can use that data. Promises have three states pending, fulfilled and rejected. And until we have no data in the promise and API execution is not completed yet till that time we will have a state pending in the promise and as soon as the createOrder() API is done with its task then it may return fulfilled or rejected state depending on the API response.

Now as soon as we will have data in the promise we will attach the processedToPayment() function with the promise and we do attach the function by using the then() function which we have on promises.

let cart = ["shirts","paints","kurta"]; 
// Only cart details passed no any callback function
const promise = api.createOrder(cart);  // line 2

promise.then(function (resultFromPromise) {
 // suppose in resultFromPromise we get orderId
 // Now we can pass this orderId to our processedToPayment()
 // assume resultFromPromise = orderId
  api.processToPayment(resultFromPromise)
})

Now here promise gives us a guarantee that it will only execute once and whatever result we get from the promise is immutable what that mean is we can pass that data here and there but we can not change the data as its immutable. Also, we need to understand that then() function will be executed as soon as we have data in promise.

// Just for knowledge this is how promise 
object looks when you console.log(promise)

  __proto__: Promise
  [[PromiseStatus]]: "pending"
  [[PromiseValue]]: undefined

In the above object, the PromiseStatus will be changed to fulfilled or rejected as soon as we have a response from API and also once whatever result we get from the promise will be stored in PromiseValue which is initially undefined. Till this point, we understood what promise is and how it is helpful but in an interview first thing we need to say is the definition of promises so let's see a few definitions of promises you can learn any one or two from them.

Few definitions of Promises

A Promise is a way to handle asynchronous operations in JavaScript.

A Promise is an object that represents the eventual completion (or failure) of an asynchronous operation. (FROM MDN DOCS)

A Promise is a container for a future value that may not be available yet.

A Promise is a way to avoid callback hell by chaining asynchronous operations together.

A Promise is a pattern that allows you to write cleaner and more maintainable asynchronous code.

We have resolved the issue of Inversion of control with promises but we have one more issue that we discussed in the last blog which is Callback Hell where we were passing the callback functions inside another callback function and because of that our code was growing horizontally rather than vertically and this is also known as Pyramid of Doom. Let's see an example of how that code looks.

//Same cart example 
api.createOrder(cart,function payment(){ 
    api.processedToPayment(function orderSummary(){
        api.orderSummery(function updateWallet(){ // One more callback
             api.updateWallet(); 
        }); // Again one more call back
    })
} )

You see how we are passing callbacks but with promises, we can solve this problem also let's see how this horizontally growing code can be solved with promises.

api.createOrder(cart)
  .then(() => {
    return api.processedToPayment();
  })
  .then(() => {
    return api.orderSummery();
  })
  .then(() => {
    return api.updateWallet();
  })
  .catch((error) => {
    console.error(error);
  });

we're using Promises instead of callbacks to handle the asynchronous operations. The createOrder() method returns a Promise that resolves when the order is created and the processedToPayement() method returns a Promise that resolves when the payment is processed.

We chain these Promises together using the .then() method, which takes a function as an argument that is called when the Promise resolves. Each .then() method returns a new Promise, which allows us to chain more .then() methods together.

If any of the Promises in the chain are rejected, we can handle the error using the .catch() method, which takes a function as an argument that is called when any of the Promises are rejected.

One thing to note here is that if any of the promises return some value and if you want to pass in the chain you must return that promise most of the time we forget to use this return keyword but understand if we need to pass that data in next level of chain then you must use return. And this way promise helps us to solve two important problems which are Inversion of control and CallBack Hell.

That's all about JavaScript Promises. And thanks to Akshay Saini for creating an incredible Namaste Javascript playlist this blog is just whatever learning I had from there.