Published on

Promises in Javascript

Overview

A blog post on Promises in Javascript.

Promises in JavaScript is almost similar to the actual meaning of Promise in English. Promises in our real day to day life are simple and straightforward. For eg: You promise your friend that you will join him for the weekend house party. But Promises in JavaScript are bit different and well structured to handle asynchronous tasks.

Lets explore JavaScript promises in detail now.

What are promises in Javascript

Promises in JavaScript is a special object that represents the success or failure of an asynchronous operation. Failure can be due to multiple reasons like network error, failed API response etc.

Promises in JavaScript has three states:

  1. pending
  2. fulfilled
  3. rejected

When JavaScript starts executing promises it is initially in the pending state. Pending state indicates the process in neither fulfilled nor rejected yet. The state will change to fulfilled when the asynchronous operation is successful. If the operation has failed due to any reason the state would change to rejected.

For an example : we send a request to a weather api to fetch the data about local weather. Once the api call is initially made the the state would be pending. If we get the results of the api call then the state changes to fulfilled. If there is any error due to any reason then the state changes to rejected.

Creating Promises in Javascript

Lets see how we can create a promise in Javascript.

example1.js
const abc = true;
const example = new Promise((resolve,reject) => {
if(abc) {
resolve("The mission is successfull")     // this block gets executed
}else {
reject("The missison failed")
}
}) ;

console.log(example)
// Promise {<fulfilled>: 'The mission is successfull'}

In the above example we have set the value of var abc as "true". The promise gets resolved because abc is "true" (if block gets executed) and the state changes to fulfilled.

The promise simply goes to the rejected state if we change the value of abc to "false"

Lets seen an another example where promise is rejected.

example2.js
const abc = false;
const example = new Promise((resolve,reject) => {
if(abc) {
resolve("The mission is successfull")
}else {
reject("The missison failed")        // this block gets executed
}
}) ;

console.log(example)
// Promise {<rejected>: 'The mission failed'}

Promise Chaining

Till now we have understood how promises work. But the real beauty lies in promise chaining. Promise chaining would allow us to define what we need to do after the promise is settled. For example - If the promise is fulfilled show congrats message on the screen and if it fails show try again message.

We can accomplish promise chaining using the following methods:

  1. then()
  2. cathch()
  3. finally()

then() is used with the callback if the promise state is fulfilled, catch() is used with the callback if the promise state is rejected. finally() method gets executed when the promise is either settled or rejected.

Lets see an example block of code below to understand the methods in a better way.

example3.js
const abc = true;
const example = new Promise((resolve,reject) => {
if(abc) {
resolve("The mission is successfull")
}else {
reject("The missison failed")        // this block gets executed
}
}) ;

// using then() -> executes if example state is fulfilled
example.then(function greet(){
console.log("The task is completed");
})

// using catch() -> executes if example state is rejected
example.catch(function greet1(){
console.log("The task failed");
})

// using finally() -> executes if example state is either fulfilled or rejected
example.finally(function greet2(){
console.log("the code is executed");
})

You can play around with the above code here - Codesandbox

We just saw how on the basis of result of the promises we can do other tasks by using Promise chaining.

Promise Methods

It is easier and straightforward to work with a single promise. But what if we have multiple promises ? It would be cumbersome to evaluate each one them separately.

Consider a simple scenario - We have to print the result of the student only if we are able get the pass or fail in all subjects(promises). We would have to evaluate each promise separately one by one. There can be different variations of this scenarios. eg- print result only if all the student passes all subjects(promises).

We have JavaScript Methods available to rescue us for such scenarios.

Lets explore them one by one.

Promise.all()

Promise.all() takes an array of input promises and returns a Single promise that resolves to an array of results of all input promises. Promise.all() would resolve only when all the input promises have resolved or if input array contains no promises. It would reject immediately if any of the input promises are rejected or produces any error. Also, it would reject entirely on the first rejection from any of the input promises or an error from non-promise.

Lets see an example to understand it better.

promiseAll.js
const promise1 = new Promise(resolve,reject)=>{
setTimeout(resolve, 100, 'hello promise 1');
}

const promise2 = 1244;

const promise3 = Promise.resolve("Peter")

Promise.all([promise1,promise2,promise3]).then((values)=>{
console.log(values)
});

// Promise{<fulfilled>}
// ['hello promise 1', 1244, 'Peter']

As you can see from the above examples Promise.all() is resolved and we get an array of resolved values of the input array containing promises.

The Promise.all() would reject entirely if any one of the original input promise is rejected due to any reason.

PromiseAll.js
const example = Promise.reject("hello");
const example1 = Promise.resolve("Good Morning");

Promise.all([example,example1])

// Promise {<rejected>:"hello"}

Promise.allSettled()

The Promise.allSettled() takes an array of promises as an input and it returns a single promise with the result of each promise which is either fulfilled or rejected. The output is in the form of an array of objects displaying status and value.

Lets see an example below:

PromiseAllSettled.js
const example = Promise.resolve("Good Morning");
const example2 = Promise.reject("Good Night");

Promise.allSettled([example,example2]).then((results) => console.log(result))

// [ {status: 'fulfilled', value: 'Good Morning'}, {status: 'rejected', reason: 'Good Night'}]

Promise.any()

Promise.any() will take an iterable of promises and it returns a single Promise which is settled as soon as any one of the promises in iterable is fulfilled with the value of fulfilled promise.

Lets see an example:

promiseAny.js
const promise1 = Promise.reject(0);
const promise2 = Promise.resolve("hello");

Promise.any([promise1,promise2]).then((results)=> console.log(results))

// "Hello"

Promise.race()

Promise.race() returns a promise that is fulfilled or rejected as soon as any one promise in the input promise array is fulfilled or rejected with the value or reason from that promise.

It is simply a race between promises. We would get to see the result of whichever promise that settles first.

Lets see an example:

promiseRace.js
const promise1 = new Promise((resolve,reject)=>{
setTimeout(resolve,400,"hello")
})

const promise2 = new Promise((resolve,reject)=>{
setTimeout(reject,200,"hi")
})

Promise.race([promise1,promise2]).then((result) => console.log(result))

// Promise{<rejected>}

In the above example both the promises are settled but promise2 is faster and hence Promise.race() returns a promise that is settled first i.e promise2.

Summary

  1. Promises in JavaScript is a special object that represents the success or failure of an asynchronous operation.
  1. A promise can have three states - pending, fulfilled or rejected.
  1. Promise chaining is used to define what needs to be done after promise is settled.
  1. JavaScript provides inbuilt promise methods to handle different scenarios while working with multiple promises.