All about promises in Javascript...

All about promises in Javascript...

Introduction

A promise is a javascript object that represents the eventual result of an asynchronous (aka async calls) operation. Before this, asynchronous calls were handled using callbacks which made things hard. It created unmanageable code, which is known as callback hell in technical terms. So, then promise came into the picture, it is nothing but an object on which we can attach callbacks and when the async operation completes successfully or produces an error if it doesn't complete.

Creating a new Promise & Working of Promise

You can create a new promise using the constructor method. It is created using the new keyword and its constructor Promise.

const myPromise = new Promise(function(resolve, reject) {    
    // Do something here and either resolve or reject
});

We need to pass a function to the Promise Constructor that we have used. That function is called the executor function which we mentioned earlier. The executor function takes two arguments, resolve and reject as input and these two are the callback functions for the executor to announce an outcome. If the promise is successful, it calls the callback function for resolve and if the promise is not successful, it calls the callback function for reject.

As discussed above, the resolve method indicates successful completion of the asynchronous task and returns the results of the task as a value. The reject method indicates an error/failure and returns the reason for failure, which is typically an error object. Javascript provides you with the resolve/ reject method and you do not need to implement it. You just need to call them from the executor function.

const myPromise=(msg,shouldRejectPromiseOrNot)=>{
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      if(shouldRejectPromiseOrNot){
        reject("Promise Unsuccessful: Error from the server")
      }
      resolve(`Promise successful: ${msg}`)
    },2000);
  })
}
myPromise("Hello User").then(res=>console.log(res)); 
//if nothing is passed then shouldRejectPromiseOrNot is false
//Output: Promise successful: Hello User
myPromise("Hello User",true).then(res=>console.log(res));
//Output: Promise Unsuccessful: Error from the server

The Promise Object and states

Now that we created our promise, we saw that either it was fulfilled or rejected. So, a promise object has the following internal properties:

  1. state: There are 2 states of promises and can have the following values
    • Pending: It is the initial state when the execution function starts.
    • Fulfilled: When the promise is resolved successfully.
    • Rejected: When the promise is not resolved and gets rejected.
  2. result: This property can have the following values:
    • undefined: Initially, when the state value is pending.
    • value: When the promise is resolved(value) successfully.
    • error: When the promise is rejected.

Note: A promise that is either resolved or rejected is called settled.

promises_settled.png

Handling Promises

We also have three important handler methods, .then(), .catch(), and .finally(). These methods help us create a link between the executor and the consumer when a promise resolves or rejected.

Different Methods of Promise

1. Promise.all()

This method takes the array of promises as an argument and returns a single promise whose resolved value will be an array of all the results of input promises, in the same order as defined.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("I am delayed by one second");
  }, 1000);
});

const promise2 = 23;

const promise3 = Promise.resolve("Success");

Promise.all([promise1, promise2, promise3])
  .then((res) => console.log(res))
  .catch((err) => console.log(err)); 

//Will resolve after 1000ms with value ["I am delayed by one second" , 23, "Success"]

But also, the promise will be rejected even if a single promise fails to resolve. Let's see an example by adding a rejected promise:

const promise4 = Promise.reject("ERROR");

Promise.all([promise1, promise2, promise3, promise4])
  .then((res) => console.log(res))
  .catch((err) => console.log(err));
/*Will be rejected right after encountering rejected promise with value "ERROR"*/

2. Promise.allSettled()

This method also takes the promises array as an argument and always resolves with an array of objects which describes the status of all the promises in the array that have either been fulfilled or rejected.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Delayed by 1000 ms");
  }, 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Delayed by 500 ms");
  }, 500);
});

const promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Delayed by 100 ms");
  }, 100);
});

const promise4 = Promise.reject("ERROR");

Promise.allSettled([promise1, promise2, promise3, promise4])
  .then((res) => console.log(res))
  .catch((err) => console.log(err));

/*Output: 
[
0: {status: 'fulfilled', value: 'Delayed by 1000 ms'},
1: {status: 'fulfilled', value: 'Delayed by 500 ms'},
2: {status: 'fulfilled', value: 'Delayed by 100 ms'},
3: {status: 'rejected', reason: 'ERROR'}
]*/

3. Promise.any()

This method also takes an iterable of Promise objects as arguments and returns a single promise that resolves as soon as any of the promises in the iterable fulfills(the one which is resolved first), with the value of the fulfilled promise. If no promises in the iterable fulfill (if all of the given promises are rejected), then the returned promise is rejected.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Delayed by 1000 ms");
  }, 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Delayed by 500 ms");
  }, 500);
});

const promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Delayed by 100 ms");
  }, 100);
});

const promise4 = Promise.reject("ERROR");

Promise.any([promise1, promise2, promise3, promise4])
  .then((res) => console.log(res))
  .catch((err) => console.log(err));

/*Output: 
/*Will resolve after 100ms with value "Delayed by 100 ms"*/

3. Promise.race()

This method also takes an iterable of Promise objects as arguments and returns the first settled value either fulfilled or rejected. Unlike Promise.any() which returns only the resolved value.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Delayed by 1000 ms");
  }, 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Delayed by 500 ms");
  }, 500);
});

const promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Delayed by 100 ms");
  }, 100);
});

const promise4 = Promise.reject("ERROR");

Promise.race([promise1, promise2, promise3, promise4])
  .then((res) => console.log(res))
  .catch((err) => console.log(err));

/*Output: 
Will be rejected right away after promise4 is rejected with value "ERROR"
*/

So this is all about promise and its methods. I hope you got a better understanding of promises. Thanks for reading.

Until next time, take care.....bye👋