Promises in JavaScript

Promises in JavaScript

ยท

5 min read

๐Ÿ“‘ Prerequisites

  • Basics of JavaScript

๐Ÿค What is the promise in JavaScript?

The promise is the object we used for the asynchronous task. it gives us the idea that either our asynchronous task is successful or failed.

The promise has 3 states:

  1. Pending: This is the initial state, which means neither fulfilled nor rejected.
  2. Fulfilled: This means the promise was resolved successfully.
  3. Rejected: This means the promise failed.

๐Ÿคž How to create promise?

The syntax to create promise is:

const promise = new Promise((resolve, reject) => {
  // Do some logic
})

The arguments resolve and reject are the callbacks provided by JavaScript itself.

  • resolve(value): The resolve is called when the request is successful with a value as a result.

  • reject(error): The reject is called when the request is failed with the error as a result.

The object returned by new Promise has these properties:

  1. state: this is "pending" initially, when resolve is called it will change to "fulfilled", and when reject is called it will change to "rejected".

  2. result: this is undefined initially, when resolve(value) is called it will change to value, and when reject(error) is called it will change to error.

๐Ÿค” How to use promise?

We can consume Promise by using the methods .then, .catch, and .finally.

1. .then

The syntax of .then is:

promise.then(
(result) => {/* use the result when promise success */ },
(error) => { /* show error if promise rejected */ }
)

The first argument of .then is called when the promise is in a fulfilled state with result as value.

The second argument of .then is called when the promise is in a rejected state with an error as value.

For example:

const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("Done"), 3000);
})

promise.then(
(result) => console.log(result), // log Done after 3 sec
(error) => console.log(error) //doesn't run 
)

And

const promise = new Promise((resolve, reject) => {
 setTimeout(() => reject(new Error("Damn error")), 3000);
})

promise.then(
(result) => console.log(result), //doesn't run 
(error) => console.log(error) // logs Damn error after 3 sec
)

If we want to handle just the result value we can use a single argument, like:

const promise = new Promise((resolve, reject) => {
 setTimeout(() => resolve("Done"), 3000);
})

promise.then((result) => console.log(result)) // log Done after 3 sec

2. .catch

As we have seen. .then will show both the result as well as the error. but what if we only want to deal with errors.

We can either use:

const promise = new Promise((resolve, reject) => {
 setTimeout(() => reject(new Error("Damn error")), 3000);
})

promise.then(null,
(error) => console.log(error) // logs Damn error after 3 sec
)

Or we can use .catch

const promise = new Promise((resolve, reject) => {
 setTimeout(() => reject(new Error("Damn error")), 3000);
})

promise.catch((error) => console.log(error)) // logs Damn error after 3 sec

3. .finally

We can use .finally when we have to execute some code even if the promise is either resolved or rejected. e.g. like stoping the loading spinner

const promise = new Promise((resolve, reject) => {
  // Do some logic
})
promise.finally(() => stop loading spinner);

๐Ÿคฏ Different promise methods

1. Promise.all()

The Promise.all() will take the array of promises as an input and return the Promise that resolves to an array of results in the same order as the input promises, if all the promises are fulfilled.

Even if the single promise is rejected, the resulting promise will reject and it will give the error/message.

const promise1 = new Promise((resolve, reject) => {
     setTimeout(() => resolve(1), 3000);
});
const promise2 = new Promise((resolve, reject) => {
     setTimeout(() => resolve(2), 2000);
});
const promise3 = new Promise((resolve, reject) => {
     setTimeout(() => resolve(3), 1000);
});

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

As you can see, even if the promise3 resolves early it will give the result at last. As it depends on the order in which you called the promises.

const promise1 = new Promise((resolve, reject) => {
     setTimeout(() => resolve(1), 3000);
});
const promise2 = new Promise((resolve, reject) => {
     setTimeout(() => reject(2), 2000);
});
const promise3 = new Promise((resolve, reject) => {
     setTimeout(() => resolve(3), 1000);
});

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

We can use Promise.all() when we have a series of asynchronous tasks which are dependent on one another.

2. Promise.allSettled()

The Promise.allSettled() will take the array of promises as an argument and return the Promise which resolves even if the input promises are fulfilled or rejected.

We can use Promise.allSettled() when we have a series of asynchronous tasks which are independent of one another.

Promise.allSettled([
  new Promise(resolve => setTimeout(() => resolve(33), 1000)),
  new Promise(resolve => setTimeout(() => resolve(66), 0)),
  99,
  Promise.reject(new Error('an error'))
])
.then(values => console.log(values));

// [
//   {status: "fulfilled", value: 33},
//   {status: "fulfilled", value: 66},
//   {status: "fulfilled", value: 99},
//   {status: "rejected",  reason: Error: an error}
// ]

If the Promise is resolved it will give the status: "fulfilled" and the value with the resolved value.

And if Promise is rejected it will give the status: "rejected" and the reason with the error message.

3. Promise.any()

Promise.any() takes the array of promises as an input and it will return the resolved Promise as soon as one of the input promises is resolved.

And if all the input promises are rejected, it will return the error as AggregateError.

Promise.any([
  new Promise(resolve => setTimeout(() => resolve(33), 1000)),
  new Promise(resolve => setTimeout(() => resolve(66), 100)),
  Promise.reject(new Error('an error'))
])
.then(values => console.log(values)); //66
Promise.any([
  Promise.reject(new Error('an error1')),
  Promise.reject(new Error('an error'))
])
.then(values => console.log(values))
.catch(error => console.log(error)) // "AggregateError: No Promise in Promise.any was resolved"

4. Promise.race()

The Promise.race() will take the array of promises as an input and return the Promise which is either fulfilled or rejected, if one of the input promises is fulfilled or rejected.

Basically, It will return the first promise which is either fulfilled or rejected.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve(33), 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve(66), 2000);
});

Promise.race([promise1, promise2]).then((value) => {
  console.log(value);
  // Both resolve, but promise1 is faster
});
// expected output: 33

๐Ÿค“ References

That's it!๐Ÿคฉ I hope you got some clarity about promises.

Thanks for reading ๐Ÿค—

thank you.gif

ย