What is a Promise?
By definition, a promise is a declaration that one will do something or that a particular thing will happen. In the programming world, a promise is an object that represents the eventual completion (or failure) of an asynchronous operation.
States
A promise can have the following states.
- Pending (Initial State, neither
fulfilled
nor ``` rejected
2. Fulfilled (The operation was a success)
3. Rejected (The operation was a failure)
A pending promise can either be fulfilled or rejected. We can attach handler methods to handle the events of promises getting ```
fulfilled
``` and ```
rejected
```. We can use the ```
then
``` method in promises to attach these handlers.
promise.then(handleSuccess, handleRejection)
We have attached two handler methods to the above promise. Now, if the promise gets fulfilled, ```
handleSuccess
``` will be called and if it gets rejected, the ```
handleRejection
``` method will be called.
When a promise is not in the ```
pending
``` state, we say the promise is ```
settled
```. Please keep in mind that being settled is merely a linguistic convenience, not a state.
# Methods
In addition, promise objects have multiple methods that can be really useful when handling promises.
## 1. Promise.all()
Input - An iterable of promises
Output - A single promise that resolves into an array of the results of the input promises
This method is useful when you have more than one promise and you want to do something only when all the operations are completed successfully. ```
Promise.all()
``` will reject immediately upon any of the input promises being rejected. For example, if you want to make multiple API calls and the code relies on all of them to be successful, you can use Promise.all()
const firstPromise = new Promise((resolve, reject) => { setTimeout(resolve, 300, "First Promise"); });
const secondPromise = new Promise((resolve, reject) => { setTimeout(resolve, 100, "Second Promise"); });
const thirdPromise = new Promise((resolve, reject) => { setTimeout(resolve, 1000, "Third Promise"); });
const rejectedPromise = Promise.reject("EVERYBODY STAY CALM. STAY F***ING CALM. I WAS REJECTED");
//Promise.all() method Promise.all([firstPromise, secondPromise, thirdPromise]) .then((results) => { console.log("All the promises were fulfilled here - ", results); }) .catch((error) => { console.error("Error: ", error); });
//Promise.all() method with a rejected promise Promise.all([firstPromise, rejectedPromise, thirdPromise]) .then((results) => { console.log("All the promises were fulfilled"); console.log("Response from all method - ", results); }) .catch((error) => { console.error("Error: ", error); });
Output
Error: EVERYBODY STAY CALM. STAY F***ING CALM. I WAS REJECTED All the promises were fulfilled here - [ 'First Promise', 'Second Promise', 'Third Promise' ]
## 2. Promise.allSettled()
Input - An iterable of promises
Output - A single promise that resolves into an array of the results of the input promises
We can use this method when the tasks are dependent on each other and you want to know all the results of all the promises regardless of the result of each promise.
//Promise.allSettled() method with a rejected promise Promise.allSettled([firstPromise, rejectedPromise, thirdPromise]) .then((results) => { console.log("I don't care if all the results are fulfilled or not"); console.log("Response from allSettled method - ", results); }) .catch((error) => { console.error("Error: ", error); });
You can clearly see the difference between the ```
all
``` and ```
allSettled
``` methods. The ```
all
``` method wants all the promises to be fulfilled while ```
allSettled
``` method only wants the promises to be ```
settled
``` (regardless of ```
fulfilled
``` or not
)
Output
I don't care if all the results are fulfilled or not Response from allSettled method - [ { status: 'fulfilled', value: 'First Promise' }, { status: 'rejected', reason: 'EVERYBODY STAY CALM. STAY F***ING CALM. I WAS REJECTED' }, { status: 'fulfilled', value: 'Third Promise' } ]
## 3. Promise.any()
Input - An iterable of promises
Output - A single promise that resolves as soon as any of the promises in the iterable fulfils, with the value of the fulfilled promise
If none of the promises gets fulfilled, a ```
AggregateError
```will reject the promise
const firstPromise = new Promise((resolve, reject) => { setTimeout(resolve, 300, "First Promise"); });
const secondPromise = new Promise((resolve, reject) => { setTimeout(resolve, 100, "Second Promise"); });
const thirdPromise = new Promise((resolve, reject) => { setTimeout(resolve, 1000, "Third Promise"); });
const rejectedPromise = Promise.reject( "EVERYBODY STAY CALM. STAY F***ING CALM. I WAS REJECTED" );
//Promise.any() Method Promise.any([firstPromise, secondPromise]) .then((fasterPromise) => { console.log("Response from any method with no rejections - ", fasterPromise); }) .catch((error) => { console.error("Error: ", error); });
//Promise.any() Method with rejections Promise.any([rejectedPromise, rejectedPromise]) .then((fasterPromise) => { console.log("Response from any method with rejections - ", fasterPromise); }) .catch((error) => { console.error("Error: ", error); });
//Promise.any() Method Promise.any([firstPromise, secondPromise]).then((fasterPromise) => { console.log("Response from any method - ", fasterPromise); });
Output
Error: [AggregateError: All promises were rejected] Response from any method with no rejections - Second Promise
## 4. Promise.race()
Input - An iterable of promises
Output - A promise that fulfils or rejects as soon as one of the promises in an iterable fulfils or rejects, with the value or reason from that promise
const firstPromise = new Promise((resolve, reject) => { setTimeout(resolve, 300, "First Promise"); });
const secondPromise = new Promise((resolve, reject) => { setTimeout(resolve, 100, "Second Promise"); });
const thirdPromise = new Promise((resolve, reject) => { setTimeout(resolve, 1000, "Third Promise"); });
const rejectedPromise = Promise.reject( "EVERYBODY STAY CALM. STAY F***ING CALM. I WAS REJECTED" );
//Promise.race() Method Promise.race([firstPromise, secondPromise]) .then((fasterPromise) => { console.log( "Response from race method with no rejections - ", fasterPromise ); }) .catch((error) => { console.error("Error: ", error); });
//Promise.race() Method with rejections Promise.race([secondPromise, rejectedPromise]) .then((fasterPromise) => { console.log("Response from race method with rejections - ", fasterPromise); }) .catch((error) => { console.error("Error: ", error); });
As the name of the method suggests, we have a race here. It does not matter whether the promises are fulfilled or rejected. The ```
race
``` method returns the fastest settled promise.
Output
Error: EVERYBODY STAY CALM. STAY F***ING CALM. I WAS REJECTED Response from race method with no rejections - Second Promise
## 5. Promise.reject() and Promise.resolve()
You are already familiar with the ```
reject
``` method since I’ve used it in earlier examples. Basically, we use the ```
reject
``` method to reject a promise.
In addition, we have the ```
resolve
``` method which returns a promise that is resolved with the given value or the promise passed as value, if the value was a promise object. Resolved is not to be confused with ```
fulfilled
```. Please read [this StackOverflow answer](https://stackoverflow.com/questions/35398365/js-promises-fulfill-vs-resolve) to learn more about it.
# Fates
Promises also have two mutually exclusive fates, resolved and unresolved.
1. If we try to resolve or reject a promise and it has no effect, we say the promise is resolved.
2. If we try to resolve or reject a promise and it has an effect, we say the promise is unresolved.
# Conclusion
To sum things up, we use promises to handle asynchronous operations in JavaScript. Especially, when there are multiple asynchronous operations running, it would be a nightmare to handle them if you don't know about promises.
I hope you learned something valuable from Today's article. If you liked it, drop a like and follow me so that you don't miss the upcoming articles. And as always, stay safe guys 😷