Hello there, have you been thinking of what the hell JavaScript promise is and what it entails? or have you been looking forward to learning more on JavaScript promises, then follow along as I will be explaining JavaScript promise right from beginners level to the quite complex ones.
To start with,
What is a Promise
Promise is a declaration or assurance that one will do something or that a particular thing will happen.
What is Promise in JavaScript
promise is a JavaScript object that allows you to run non-blocking (popularly known as async) code. It produces a value that the async operation completes successfully or produce an error if it does not complete.
In other words, the Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
A JavaScript promise has three states/ operates in three states,
- Pending: is the initial state, neither fulfilled nor rejected
- Fulfilled: means that the operation was completed successfully. (Resolved)
- Rejected: means that the operation failed.
The eventual state of a pending promise can either be fulfilled with a value or rejected with a reason (error). When either of these options occur, the associated handlers queued up by a promise's then method are called. If the promise has already been fulfilled or rejected when a corresponding handler is attached, the handler will be called, so there is no race condition between an asynchronous operation completing and its handlers being attached.
Let's look at an example to explain:
const dataPromise = new Promise((resolve, reject) => {
setTimeout( () => resolve('Show when resolved'), 1000 );
})
dataPromise.then(result => {
console.log(result);
});
.catch(error => console.log(error))
console.log('This will run before the promise')
// console ---->
// 'This will run before the promise'
// 'Show when resolved'
Looking at what we have above, if you haven't worked with promises before, you might be thinking the first console.log is supposed to come first the the other one which is not right. There are instances when we will like to check if we get what we want then return either the response or error which is where JavaScript comes in.
When we create a new Promise it will run the given callback parallel to the rest of the code in the script.
The callback will get two functions as arguments: resolve and reject, when the callback succeed in it's task then it call resolve else call reject
We then can run specific code depending whether the promise succeed or not using .then and .catch
JavaScript fetch
The most popular and common use of promise is the JavaScript fetch method that is used for fetching data from a REST API
For Example:
fetch('https://getmesomedata.com/dummy') //pending
// resolved?
.then(response => response.json())
// rejected?
.catch(error => console.log(error))
How it works
The fetch API from JavaScript return a Promise because considering the time it will take to get response from our server using HTTP request which may be fast or otherwise slow, so we need something (promise) to handle some functions if we are able to get our data and also an handler to trigger an error when the request fails
This is still very basic as it can get complex as the case may be and we will touch a bit of it as we move on.
JavaScript Promise graph
We can declare a promise in two ways
- Assigning the promise to a variable
const promise = new Promise((resolve, reject) => {
// the promise will return pending when the data is being fetched or the action stated is being executed
// When the promise is resolved (the request was successful)
resolve(data)
// When the promise get rejected (the request failed)
reject(error)
});
promise.then((data) => {
// This will execute once the request is successful
});
promise.catch((error) => {
// This will execute when the request fails
})
promise.finally(() => {
// This will run both if the promise get resolved or it get rejected
})
- Chaining the promise response Instead of declaring instances for each response, we can chain them together
promise.then((data) => {
// This will execute once the request is successful
})
.catch((error) => {
// This will execute when the request fails
})
.finally(() => {
// This will run both if the promise get resolved or it get rejected
})
You can use anyone base on preference or just play around with the two
Moving on...
The return value of .then, .catch and .finally also returns a Promise instance so therefore allowing us to chain more of this promise handlers.
Here is an example:
new Promise(function(resolve, reject) {
setTimeout( () => resolve(1), 1000);
}).then(function(result) {
console.log(result); // 1
return result * 2;
}).then(function(result) {
console.log(result); // 2
return result * 2
}).then(function(result) {
console.log(result); // 4
return result * 2
});
It can continue like that but be mindful not to overdo it
This can be application when fetching a large data from our API and we need to perform some operations on it before returning it to the document body. Sounds cool right?
Moving on to the quite advance ones...
The .then() handler can also return a newly created Promise instance. This can be used in a situation where you need to make multiple API calls in an asynchronous way whereby the other fetch request will get called only when the previous one was successful.
Here is an example
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
}).then(function(result) {
console.log(result); // 1
return new Promise((resolve, reject) => {
setTimeout(() => resolve(result * 2), 1000);
});
}).then(function(result) {
console.log(result); // 2
return new Promise((resolve, reject) => {
setTimeout(() => resolve(result * 2), 1000);
});
}).then(function(result) {
console.log(result); // 4
});
And it can continue like that depending on your app size. Sounds great right?
Feel free to get your hands dirty with different JavaScript Promise instances.
Don't forget to like and follow for more amazing content