Hii 👋everyone, Today I'm going to explain each and everything about promises in this blog.
People always think promises are hard part in javascript but once you are clear with concepts it will be the easiest. If you are going for an interview your interviewer will love promises. Don't worry you'll be able to understand all concepts.
In this blog we are going to cover promises from basic to advance in a beginner friendly way. Things to be covered:-
What is Promise
A Promise is a proxy for a value. It allows you to associate handlers with an asynchronous action's eventual success value or failure reason. This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future. Let's understand this with help of an example:-
Restaurant Example
I'm a food lover😋may be you too. Let's start with this example then.
Suppose you wanted to eat some delicious food so you went to a restaurant and ordered pizza for yourself. Now the cashier took your order and gave you a token that your food will be delivered shortly. Token is not food, it’s not a value, but it’s a future value. The cashier (or the waiter) gave you a promise that he is going to send you back your meal. When? it can take a few seconds or minutes just as it can take an hour. It all depends on how quick are the cookers and how many people are already waiting in the queue. Now there are two cases
- Either your meal will be delivered to you in some time.
- Or In the worst-case scenario, the waiter will come and tell you that they ran out of cheese 😫 Maybe then you can order something else.
Note:- When you have ordered the meal waiter will not sit ideal and wait for your meal to get ready. He will take other customers orders also and give them to the cook.
The same goes for promises, you execute some asynchronous code (like sending a request to the server from the client-side) and you wait for your response. Meanwhile, you’ll get a promise to future data in return. Either your request will be fulfilled or it will be rejected.
When the pizza (or the data) is finally ready, you can then start eating it and enjoying the taste. Otherwise, you may order something else or visit another restaurant that still has some cheese left.
The JavaScript promises also work similarly. As developers, we create them to fetch something(data from a data store, configurations, and many more). Usually, the fetching may not happen instantly. We want to fetch things asynchronously. It means we do not want the application to wait for the response, but we can continue to work on the response when it is available.
Don't worry if some of the terms looking new or confusing to you. We will revisit it at the end of this article.
Promise in JavaScript
A promise is a JavaScript object that allows you to make asynchronous(async) calls. It produces a value when the async operation completes successfully or produces an error if it doesn't complete.
You can create promise using the constructor method,
let promise = new Promise(function(resolve, reject) {
// Do something and either resolve or reject
});
We need to pass a function to the Promise Constructor. That function is called the executor function(Remember, fetching the water?). The executor function takes two arguments, resolve and reject. These two are callback functions for the executor to announce an outcome.
The resolve method indicates successful completion of the task(fetching water), and the reject method indicates an error(the disaster). You do not implement the resolve/reject method. JavaScript provides it to you. You need to call them from the executor function.
So, in case of the Jack and Jill story, the executor function may look like,
- Example of the resolve:
let promise = new Promise(function(resolve, reject) {
// Got the water
let value = 'water';
resolve(value); // An assurance of getting the water successfully
});
- Example of the reject:
let promise = new Promise(function(resolve, reject) {
// OOPS, Jack fell down and broke his crown.
// And Jill came tumbling after.
reject(new Error("Disaster")); // Throwing and error
});
States in Promise
In the restaurant example, the waiter was not waiting for your order to get ready then he will take other's order. In the mean time when your order was cooking he was taking order of others. But chef will inform him when your order is ready or they are out of cheese so your order can't be prepared.
Similarly, the promise object should be capable of informing the consumers when the execution has been started, completed (resolved), or returned with error (rejected).
A promise object has the following internal properties,
state: This property can have the following values,
pending: When the execution function starts. In our story, when Jack and Jill start to fetch the water.
- fulfilled: When the promise resolves successfully. Like, Jack and Jill are back with the water.
rejected: When the promise rejects. Example. Jack and Jill couldn't complete the mission.
result: This property can have the following values,
- undefined: Initially, when the state value is pending.
- value: When the promise is resolved(value).
- error: When the promise is rejected.
- A promise that is either resolved or rejected is called settled.
So the consumers need to rely on the promise object to know the state and value/error.
How to deal with errors in Promise
The promise object returned by new Promise constructor has all data in it. Where you can check whether the promise is rejected or fulfilled and you can also get the data from the object itself.
But wait! These properties are internal. It means that we will be able to inspect the state and result property values using a debugger tool, but we will not be able to access them directly using the program.
So then? That's where we 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 rejects.
.then() Promise Handler
We get a .then() method from every promise. The sole purpose of this method is to let the consumer know about the outcome of a promise. It accepts two functions as arguments, result and error.
(result) => {
console.log(result);
},
(error) => {
console.log(error);
}
);
Also note, you can do three very exceptional things inside the .then() method,
- You can return another promise from it.
- You can return a value including undefined.
- You can throw an error.
These three points will be the basis of learning the Promise Chain in the future article.
.catch() Promise Handler
You can use this handler method to handle errors (rejections) from promises. As we discussed already, it is a much better syntax to handle the error situation than handling it using the .then() method. So let us now handle the "Jack fell down..." situation using JavaScript promise.
```// 1. Create the promise let promise = new Promise(function(resolve, reject) { setTimeout(function() { // Reject it as the disaster happend. reject(new Error('Jack fell down and broke his crown. And Jill came tumbling after.')); }, 2000); });
// 2. Inform grandparents
// but this time we are using the .catch
const grandParentsCooking = () => {
promise.catch(function(error) {
console.error(OMG ${error.message}
);
});
}
// 3. Call the function grandParentsCooking();
The Output:-
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1652201850559/97EzDDpPV.png align="left")
- We use the .catch() handler to handle the rejection. In the real world, you will have both .then() and .catch() methods to handle the resolve and reject scenarios. We will learn it in the promise chaining article of the series.
# .finally() Promise Handler
The .finally() handler method performs cleanups like stopping a loader, closing a live connection, and so on. Irrespective of whether a promise resolves or rejects, the .finally() method will be called.
```let loading = true;
loading && console.log('Loading...');
// Getting the promise
promise = getPromise();
promise.finally(() => {
loading = false;
console.log(`Promise Settled and loading is ${loading}`);
}).then((result) => {
console.log({result});
});
The vital point to note, the .finally() method passes through the result or error to the next handler, which can call a .then() or .catch() again. It is convenient, and we will see many examples of it in the promise chain article.
Misktakes you make in using Promises
Avoid Promise Hell
Usually, Promises are used to avoid callback hell. But misusing them can cause Promise Hell.
getArticle(user).then(function(articles){
showArticle(articles).then(function(){
//Your code goes here...
});
});
});
In the above example, we have nested three Promises to userLogin, getArticle, and showArticle. As you can see, the complexity will grow proportionally to the lines of code and, it could become unreadable.
To avoid this we need to un-nest our code by returning getArticle from the first then and handle it in the second then .
.then(getArticle)
.then(showArticle)
.then(function(){
//Your code goes here...
});
In Summary
To Summarize,
- Promise is an important building block for the asynchronous concept in JavaScript.
- You can create a promise using the constructor function.
- The constructor accepts an executor function as an argument and returns a promise object.
- A promise object has two internal properties, state and result. These properties are not code-accessible.
- The consumer of a promise can use the .then(), .catch(), and .finally() methods to handle promises.
- The Promise is better understood using examples, like the restaurant example.
That's all for now. Please stay tuned for the second article of the series. We will learn about the Promise Chain with another story.