Promise is one of the most essential concept to understand in JavaScript, yet it remains a challenging concept to grasp. Promise assist us to handle asynchronous operations in JavaScript.
The concept of asynchronous in JavaScript enables us to break down complex projects into minor tasks.
We subsequently use any of these procedures : callbacks
, promise
or async/await
to execute these minor tasks more effectively.
In this article, I intend to explain Promise to you in an easy-to-understand procedure. The article will explore the ensuing concepts
- Asynchronous and Synchronous operations
- Callback and Callback hell
- Promise and the Promise lifecycle
- Promise Chaining
- Promise error handling
Before we dive into Promise, we need to first understand synchronous and asynchronous operations in JavaScript.
Synchronous and Asynchronous Operations
JavaScript is a single-thread language, because it is single-threaded, it only authorizes one logic to be performed at a time. Code execution is in sequence, and must complete executing a statement before moving on to the next statement.
The procedure defined above makes the operations in JavaScript synchronous.
Understanding Synchronous Operations
In a synchronous system, tasks are completed one after the other.
Consider a scenario where you are tasked to lift 5 buckets filled with water at varying levels from one destination to the other, and empty it into a bigger reservoir.
As long as you have only one hand, you complete the lifting of one bucket to its destination, pour the water into the required reservoir, before moving on to lift and empty the next bucket into the reservoir.
Tasks are being completed one after the other making it synchronous
There is always a challenge in performing these tasks one after the other (lifting, moving and emptying the buckets into the reservoir).
For example, if there is difficulty in lifting the third bucket due to the high volume of water in it, it will prevent the completion of the other tasks. The other buckets (buckets 4 to 10) will have to wait for the current bucket to be moved to its destination and emptied into the reservoir before their session begins.
In effect, the third bucket is delaying its task hence blocking all the remaining tasks from being completed.
From the scenario above, if tasks are being completed one after the other in JavaScript, the procedure is synchronous, and synchronous operations in JavaScript is blocking.
For example, if a statement takes a while to execute, it will freeze the other statements from completing.
Let's take a look at Asynchronous operations.
Understanding Asynchronous Operations
JavaScript is a single-threaded language, however, JavaScript can behave as if it were multi-threaded and non-blocking. This means that, it doesn't wait for the response of an API call, I/O events, etc., and can proceed the code execution.
Asynchronous programming is a technique that enables your program to start a potentially long-running task, and still be able to be responsive to other events while that task runs, rather than having to wait until that task has finished. Once that task has finished, your application is presented with the result.
Let's explore this technique further.
Take the same scenario where you have 5 buckets filled with water at different levels. But in this scenario, you have 5 helping hands (multiple hands) to lift the buckets from a point to their destination, and empty into the reservoir.
Because you have 5 helping hands, each hand can perform its task independently.
If one hand struggles to lift it assigned bucket to its destination due to the volume of water it contains, it can take all the time it needs to lift and empty the bucket into the reservoir, and this will not stop the other hands from completing their tasks.
With the scenario above, each task is complete independently, making it asynchronous.
Asynchronous operations in JavaScript is non-blocking. Meaning, if a statement takes a while to execute, it will not block the other statements from completing.
The challenge with long-running synchronous function.
In the above, we explored both synchronous and asynchronous operations in JavaScript.
To recap:
- In synchronous operations: tasks are *performed one after the other, and is blocking *
- In asynchronous operations: tasks are performed independently of other tasks, and is non-blocking
Let's explore some challenges we might encounter with synchronous operations.
What if a synchronous operation takes a long time to complete, and there is a task which depends on an output from our earlier task (which is delaying).
What will happen to the rest of our tasks?
Well, we have no option, but to wait for the long running task to complete, before we can move on.
This will freeze or block all the other tasks that might depend on the output of our long running task
To figure out the issue of freezing our application, we need a way for our application to:
- Commence a long-running or delaying operation by calling a function. This function will execute when the delaying operation has completed.
- Inform us with the result of the long-running operation when it eventually completes.
- Run the other tasks independently.
That's exactly what asynchronous functions try to solve. If a function takes some time to complete its task, the rest of the code below that function can still run whiles the function is in progress, making our application non-blocking
Example of asynchronous operation
// Declare some functions
function foo() {
console.log("foo")
}
function bar() {
console.log("bar")
}
//Executes the functions below
setTimeout(foo,2000) //Delays for 2s then executes foo
console.log("Faz")
bar()
By default, the execution of the code above should be synchronous and blocking, meaning tasks should executed one after the other.
See the illustration below:
Because setTimeout()
function will wait for 2s before running the foo
, it should block or freeze the other codes below it from executing.
However, the output of the code is:
"Faz"
"bar"
"foo"
Due to the JavaScript event-loop behavior, the entire code executes asynchronously and non-blocking.
This occurs because the event loop first executes all synchronous code and at the same time, running the setTimeout()
in the background.
In the background, it waits for 2 seconds for the setTimeout()
to complete, and when it's done, puts the callback that we passed as an argument in something called the task queue where it will be added to the call stack and executed.
Hence, the program above is executed independently and is non-blocking
Understanding callback functions?
One approach to asynchronous programming, is to make functions that perform a slow action take an extra argument, a callback function. The action is started in the background, and when it finishes, the callback function is called.
In the code above, you will notice, we passed foo
as an argument to the setTimeout()
function.
A callback is a function that's passed into another function, with the expectation that, the passed function will be called at the appropriate time.
The code below illustrates callback
function task1(call_task2){
console.log("Start task1, when done, start task2 ")
//call task 2
call_task2()
}
function task2(){
console.log("Task2 has started...")
}
//pass task2 to task1
task1(task2)
The output of the code above will be
"Start task1, when done, start task2 "
"Task2 has started..."
Importance of callback functions ?
We have learnt what a callback function is, but why do we need callback
functions?
When performing a complex task, we break that task down into minor steps. To create a connection amongst these steps based on their order and time taken (optional), we use callback functions.
Use case of callback function
To better understand callback functions
, let's imagine we run a fried rice street food business, where customers can order our delicious fried rice.
Below we have outlined the steps to prepare our fried rice when the customer places an order
Steps in preparing fried rice
- Customer orders fried rice
- Preparation begins
- Chop and prepare the ingredients ----- 3 seconds
- Season the meat and prepare the egg and rice ------ 2 seconds
- Mix the ingredients ------ 2 seconds
- Add soy sauce, oyster sauce, and salt to taste ------ 1 second
- Serve customer ----- 2 seconds
For our streetfood business to be profitable:
- The customer first orders the fried rice, and then we begin the production.
Let's establish a relationship between the ordering and the preparing of the fried rice.
See the code below:
function customerOrders(call_back){
console.log("Customer places order")
//call startProducing
call_back()
}
function startProducing(){
console.log("Begin fried rice preparation")
}
//pass startProducing function to customerOrders
customerOrders(startProducing)
In the code above:
- We defined a
customerOrders()
function to indicate the customer has placed an order - We defined a
startProducing()
function to start preparing the fried rice - To establish a relationship between the ordering and preparation of the fried rice, we will use a
callback
function. Once, the order has been placed, then we will start the preparation - To achieve the above, we will pass the
startProducing
function as an argument to thecustomerOrders
function.
The output of the code above will be :
"Customer places order"
"Begin fried rice preparation"
Let's assume the customer is undecided, so he waits for 2 seconds before placing the order.After 2 seconds, the order will be placed, and we can start preparing our delicious fried rice.
Let's expand our code to accommodate the 2 seconds delay using the setTimout()
function.
function customerOrders(call_back){
//wait for 2 seconds and runs the inner function
setTimeout(function(){
console.log("Customer places order")
//call startProducing function
call_back()
},2000)
}
function startProducing(){
console.log("Begin fried rice preparation")
}
customerOrders(startProducing)
- We have still kept the relationship between ordering and preparation of the fried rice by passing the
startProducing
as the callback function tocustomerOrders
.
We also introduce another aspect, the time it takes before the customer places an order.
- The
setTimeout()
is another function we are nesting into thecustomerOrders()
function. - When the
customerOrders()
function is executed, it will run thesetTimeout
function in the background - After two seconds delay, the function passed to the
setTimeout
will execute.
Note: In the body of that function, we finally run our startProducting
function.
Because we are passing functions to other functions, and running functions in functions, we are effectively creating callback functions. The key takeaway is, there is a link between all these functions.
So far, we have used callback functions to perform to important steps:
- Allow 2 seconds delay, and then customer places an order
- Start preparing the fried rice, when customer places an order.
Now that the customer has placed the order, let's start preparing the fried rice.
We will insert all the specific tasks to be carried out in preparing the fried rice in our startProducing
function. This is to form a connnection between each task.
Because each individual task takes some time to complete, we will use the setTimeout
function to stimulate the time it takes to perform that task in the background.
After the task has been completed, we will inform the customer about the action that has been taken.
The snippet for the setTimeout
function is as below:
setTimeout(function(){
//code goes here
}, 2000); //Time before execution
Let's expand our code to include the specific tasks to be performed.
- For our first task, it will take 3 seconds to complete the process. After the duration has elapse, we will execute the code passed to the
setTimeout
//customer places order
function customerOrders(call_back) {
//wait for 2 seconds
setTimeout(function () {
console.log("Customer places order");
//start preparing the fried rice.
call_back();
}, 2000);
}
//start fried rice preparation
function startProducing() {
setTimeout(function () {
console.log("Begin fried rice preparation");
//delay for 3s and run the function
setTimeout(function () {
console.log("Chopped and prepared the ingredients");
}, 3000);
}, 0000);
}
//run the tasks
customerOrders(startProducing);
The output will be:
"Customer places order"
"Begin fried rice preparation"
"Chopped and prepared the ingredients"
Let's complete the preparation of our fried rice in the startProducing()
function by merging each next step to take inside the previous step.This will help establish a link between each step.
The illustration for the code execution is as below:
The entire code is as below:
function customerOrders(call_back) {
//customer wait for 2 seconds
setTimeout(function () {
console.log("Customer places order");
//call startProducing function
call_back();
}, 2000);
}
// Start preparing the fried rice
function startProducing() {
//step 1
setTimeout(function () {
console.log("Begin fried rice preparation");
//step 2
setTimeout(function () {
console.log("Chopped and prepared ingredients");
// step 3
setTimeout(function () {
console.log("Seasoned the meat and have prepared the egg and rice");
//step 4
setTimeout(function () {
console.log("Ingredients have been mixed");
//step 5
setTimeout(function () {
console.log("Added soy sauce, oyster sauce, and salt to taste");
//step 6
setTimeout(function () {
console.log("Serving the delicious fried rice");
}, 2000);
}, 1000);
}, 4000);
}, 2000);
}, 3000);
}, 0000);
}
customerOrders(startProducing);
The output of the code will be :
"Customer places order"
"Begin fried rice preparation"
"Chopped and prepared ingredients"
"Seasoned the meat and have prepared the egg and rice"
"Ingredients have been mixed"
"Added soy sauce, oyster sauce, and salt to taste"
"Serving the delicious fried rice"
We have learnt how to perform a sequence of tasks using callback functions.
We can use the same callback function technique,when fetching multiple data from an api. Where we rely on the result of the initial api call to perform the next action.
But this approach introduces another layer of complexity.
Let's explore further.
Welcome to callback hell
Eventhough we have been able to prepare our delicious fried rice, the code above looks messy. We needed to nest callback **into **callback **into **callback. This phenomenon is termed callback hell
.
Callback hell is the situation where callbacks are nested within other callbacks several levels deep, potentially making it difficult to understand and maintain the code.
Can you spot the pyramid shape highlight in the yellow section below, and all the })
at the end of our program? This is graciously known as callback hell.
If we nest callbacks in such a way describe above, we are more likely to write, difficult to read, error prone and difficult to maintain code. The solution is to use Promise
to handle each tasks.
In the next section, we dive into Promise
Introducing Promise
In an asychronous operation (tasks that takes sometime to complete), instead of arranging for a function to be called at a later time (callback function), you can return an object that represents a future value.
The return object is what we call Promise
.This object represents the future completion (or failure) of an asynchronous operation and its resulting value.
In simple terms, a Promise
is container for a future value. An example of a future value is a response from an AJAX call or fetching data from an API using the fetch()
method.
A promise is an asynchronous action that may complete at some point and produce a value. It is able to notify anyone who is interested when its value is accessible. We can also define Promise, as an object that is used as a placeholder for the future result of an asynchronous operation.
Promise analogy
We can appreciate the concept of Promise using the analogy below:
- When you place a bet on a football match, there is a *promise * that you will receive money if you guess the correct outcome of the game.
- So you purchase the betting slip (promise) right away.
- On match day, if you guess the correct outcome, you will receive the money,because it was promised.
Using our initial fried rice scenario,if a customer places an order for our delicious fried rice, we will give the customer something to hold on to (for instance a slip).
The slip is a promise to the customer we would get him our delicious fried rice, if he orders now.
With this assurance, he can wait for sometime as we prepare the fried rice.
We promise to attend to the customer in any case:
- If we were able to prepare the fried rice, the customer is informed, and he can enjoy his fried rice
- If something happened (perhaps, we did not have enough rice), and we couldn't prepare the fried rice, we will still notify the customer, and the customer goes home disappointed.
Advantages of Promise
- Using Promise, we no longer need to rely on events and callbacks passed into asynchronous functions to handle asynchronous results.
- Instead of nesting callbacks, we can chain promises for a sequence of asynchronous operations; escaping callback hell.
Creating a Promise
The syntax for creating a Promise
is as below:
let success = true;
let promise = new Promise(function(resolve, reject) {
// perform an asynchronous operation here...
//return state of the promise
if (success) {
resolve(value);
} else {
reject(error);
}
});
Let's understand the code above:
- We call the
new Promise()
constructor and pass it a callback function as an argument - The callback passed to the
new Promise()
is the executor, and is responsible for performing an asynchronous operation. - The callback accept two parameters,
resolve
andreject
- Inside the body of the callback, we perform any asynchronous operation such as fetching data from an API.
- If the asynchronous operation successfully completes, and we get some kind of value, we will call the
resolve()
function and pass it the value. - If the asynchronous operation was unsuccessfull perhaps due some slow internet connectivity, we will call the
reject()
function, and pass it the error.
The returned value of new Promise()
is an Object
, this Object
serves as a placeholder for value we will get back from the asynchronous operation.
Understanding the Promise Lifecycle
- Whiles the asynchronous task in being carried, the
Promise Object
returned, will have aState
property with an inital value ofPending
- When the asynchronous task completes, the value of the
State
property updates toSettled
- If the asynchronous task was successful, the
State
property updates tofulfilled
- If the asynchronous task was unsuccessful, the
State
property updates torejected
- There is also a
result
property in the Promise object. It is initially set toundefined
, then changes to the value we got from the asynchronous operation whenresolve()
is called orerror
whenreject(error)
is called.
The examine that new Promise()
constructor function returns a Promise Object
const promise = new Promise((resolve,reject)=>{
})
console.log(promise)
The output of the code above will be
To sum up,the callback function we pass to the
new Promise()
constructor runs automatically and attempts to perform a task.** When it is done with the attempt, it callsresolve()
if it was successful orreject()
if there was an error.**
Examine the code below:
const getSomething = ()=> {
return new Promise(function(resolve,reject){
// perform some async operation here...
let success = true // Stimulate successful async operation
if (success) {
resolve("data"); // pass the value you got from the async operation
} else {
reject(error); // pass the error if unsuccessful
}
})
}
console.log(getSomething())
- We declared the
getSomething
function, in the body of the function, we call thenew Promise
constructor function - We passed the callback function, and it the body of the callback, we perform the asynchronous operation.
- If the operation was successful, we call the
resolve()
and pass it the data we got from the async operation. - If the operation was unsuccessful, we call the
reject()
and pass it the error we got from the async operation.
Below will be the result of the code above:
Promise and the fetch API.
Inside of using the AJAX call to make a request for resources on a web server, the global fetch()
method provides an easy and logical way to fetch resouces asynchronously across the network.
When the fetch()
method is executed, it immediately returns a Promise Object
, and goes through the Promise lifecyle as described above.
A basic fetch request is easy to set up:
const promise = fetch('http://www.example.com')
console.log(promise)
The output will be
Consuming Promises using the then()
method
We need to find a way of utilizing the Promise Object
returned after the completion of the asynchronous task.The then()
method will help with that
To get the value of a promise when it’s fulfilled, you call the
then()
method of the promise object.
The following shows the syntax of the then()
method:
// consuming the promise object
promise.then(
function(result) { /* handle a successful result */ },
function(error) { /* handle an error */ }
);
- In the
then()
method, we accept two callback functions. - If the
Promise State
is fulfilled, we run the first function. In the function we accept one parameter, theresult
of the asynchronous task. We can now make use of theresult
. - If the
Promise State
is rejected, we run the second function,it also accept theerror
we got from the asynchronous task as a parameter.
Examine the code below:
const getSomething = ()=>{
return new Promise((resolve,reject)=> {
// perform some async operation here...
let success = true //async operation was successful
if (success) {
resolve("We got some data back");
} else {
reject("Oops Error fetching data");
}
})
})
}
//get the value of the promise object using then()
getSomething().then(
function onFulfilled(result){
/* handle a successful result */
console.log(result)
}, function onRejected(error){
/* handle an error*/
console.log(error)
})
Let's understand the code above:
- We utilize the
then()
method to consume or make use of what we have in thePromise object
.Whether the asynchronous operation was successful or not, we want to know and take some action. - The first argument of the
.then()
is a function that runs when the promise is fulfilled. - The second argument of the
.then()
is a function that runs when the promise is *rejected * - If we are interested in only the successful completion, we can insert only one callback function in the
.then()
method. - In the code above, we pass to the
.then()
method both theonFulfilled
function andonRejected
function. - In the body of the function, we can log the result or the error if any.
The output of the code above will be:
Another example using the fetch()
method
const result = fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json(), error => console.log(error) )
console.log(result)
The output will be:
Using the .catch()
method to handle errors
If we are interested only in the error when the Promise is rejected
, we can use the catch()
method of the Promise object to "catch" the error
promise.catch((error) => {
console.log(error);
});
We can rewrite the code above as :
const getSomething = ()=> {
return new Promise((resolve,reject)=> {
// perform some async operation here...
let success = false //async operation was unsuccessful
if (success) {
resolve("We got some data back");
} else {
reject("Opps Error fetching data");
}
})
}
//get the value of the promise object using then()
getSomething().then(
function onFulfilled(result){
/* handle a successful result */
console.log(result)
}).catch((error)=>{
/* handle a unsuccessful result */
console.log(error)
})
Using the fetch()
method
const result = fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json()).catch(error => console.log(error))
console.log(result)
Promise Chaining
Often, we need to execute two or more related asynchronous tasks. When the previous task succeeds, we want to start the next task with the result of the previous task. Promise chaining help us to accomplish that.
Examine the code below:
const doSomething = ()=>{
return new Promise((resolve,reject)=>{
//stimulate asynchronous operation
setTimeout(function(){
resolve(10)
},3000)
})
}
//consume the returned promise object
const secondPromise = doSomething().then((result)=>{
console.log(`Result is ${result}`)
//dosomething else with the result and return the update Promise object
return result*2
})
console.log('secondPromise Object',secondPromise)
- In the code above, we used the
setTimeout
function to stimulate an asynchronous task. - We wait for 3 seconds, and if the asynchronous task was successful, we call the
resolve()
method, and pass it a value of10
. - We get back a
Promise Object
withPromiseState
andPromiseResult
properties. - Since the operation was successful, we change the
PromiseState
property of the Promise object fromPending
tofulfilled
, and thePromiseResult
to10
. - In the
then()
method we can make use of the Promise object, we implement a callback function have access to thePromiseResult
and log it to the console.
What if we want to perform another task with the PromiseResult
, how do we handle that ?
- We can update the value in the
PromiseResult
and then return the Promise object.
//update the result and return the Promise object
return result * 2
To examine that, the then()
method can ** return updated Promise object,** we can assign the returned Promise object to the secondPromise
variable.
- From the above screenshot, the Promise Object was updated, and now has a
PromiseResult
of20
. - We can even update this result by chaining another .then() method or simply log the result to the console.
See the modified code below
const doSomething = ()=>{
return new Promise((resolve,reject)=>{
//stimulate asynchronous operation
setTimeout(function(){
resolve(10)
},3000)
})
}
//consume the promise object using promise chaining
doSomething().then((result)=>{
console.log(`Result is ${result}`)
//dosomething else with the result
return result*2
}).then((nextResult)=> {
// then do something else again
console.log(`The next operation resulted in ${nextResult}`)
})
The output will be:
"Result is 10"
"The next operation resulted in 20"
How did we arrive at the about output?
- The first .then() method returned a Promise object, this Promise object was utilized by the second
.then()
method. - We can keep calling successive
then()
method whiles returning the Promise Object.
Essentially
Promise chaining
, is linking a series ofthen()
method to define what needs to be done when the previous promise is fulfilled.
Basically, each promise represents the completion of another asynchronous step in the chain.
Promise chaining works this way:
- If our first task is complete, *then * we do the other task, **then **we do the next task, **then **the next, **then **the next etc.
The below illustrates Promise chaining using the fetch()
method
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(json => console.log(json))
- Our first
then()
returns a Promise Object with a fulfilled state, we can chain a newthen()
do something else with the result returned by the previousthen()
In time past, performing several asynchronous operations in a row would lead to the classic callback pyramid of doom.
Solving the callback hell using Promise chaining
Let's now see how to use Promise to solve our Callback hell encounted in our Fried rice scenario
If the shop is open, the customer waits for 2 seconds and makes his order.
Below is how to illustrate this process using Promises:
const customerOrder = (time, task)=>{
let isOpen = true;
return new Promise((resolve,reject)=>{
if(isOpen){
setTimeout(()=>{
//run first task if async operation is successful
resolve(task())
},time)
}else {
reject("shop is closed")
}
})
}
customerOrder(2000,()=>{console.log('Customer places order')})
- If the shop is open, the customer waits for 2 seconds and places the order
- We pass two arguments to the
customerOrder
function- First is the duration it takes to complete the task
- Second, the task to perform
- The actual task will be performed in the
resolve()
method, doing this, we get access to the fulfilled Promise object
Now, instead of nesting callback into callback, we are going to use Promise
chaining to define what needs to be done when the customer places an order.
Think of it as giving instructions to your cooks on what needs to be done after the customer places an order.
- You tell the cook to "Do this task first, then **do the next task, **then **this other task, **then..., then..., then..." etc.
The entire process is captured below:
- When the
customerOrder()
function is executed, it returns ourPromise Object
. - The
Promise Object
will indicate whether our promise is fulfilled or rejected. - If fulfilled, we run our tasks.
- Each of our tasks will be in the
then()
method. - For each task, we will return our updated Promise Object.
The complete code is as below:
const customerOrder = (time, task) => {
let isOpen = true;
return new Promise((resolve, reject) => {
if (isOpen) {
setTimeout(() => {
//run each task here if shop is open
resolve(task());
}, time);
} else {
reject("shop is closed");
}
});
};
customerOrder(2000, () => {
console.log("Customer places order");
})
// then task 1
.then(() => {
return customerOrder(0000, () => {
console.log("Begin fried rice preparation");
});
})
// then task 2
.then(() => {
return customerOrder(3000, () => {
console.log("chopped and prepared the ingredient");
});
})
// then task 3
.then(() => {
return customerOrder(2000, () => {
console.log("seasoned the meat and prepared egg stew");
});
})
// then task 4
.then(() => {
return customerOrder(4000, () => {
console.log("Ingredients have been mixed");
});
})
// then task 5
.then(() => {
return customerOrder(1000, () => {
console.log("Added soy sauce, oyster sauce, and salt to taste");
});
})
// then task 6
.then(() => {
return customerOrder(2000, () => {
console.log("Serving the delicious fried rice");
});
})
.finally(() => {
console.log("Thank you for stopping by ");
});
The output will be:
"Customer places order"
"Begin fried rice preparation"
"chopped and prepared ingredient"
"seasoned the meat and prepared egg stew"
"Ingredients have been mixed"
"Added soy sauce, oyster sauce, and salt to taste"
"Serving the delicious fried rice"
"Thank you for stopping by "
The .finally() method
Occasionally you want to execute similar function whether the promise is fulfilled or rejected.
Examine the code below:
const doSomething = ()=>{
// let run some task here
}
const getSomething = ()=> {
return new Promise((resolve,reject)=> {
// perform some async operation here...
let success = false //async operation was unsuccessful
if (success) {
resolve("We got some data back");
} else {
reject("Opps Error fetching data");
}
})
}
//get the value of the promise object using then()
getSomething().then(
(result)=> {
/* handle a successful result */
console.log(result)
// call doSomething
doSomething()
}
).catch((error)=>{
/*handle an unsuccessful task */
console.log(error)
// call doSomething
doSomething()
})
Notice that, doSomething()
function is duplicated in the both the then()
method and catch()
method.
To take out this duplication and execute the
doSomething()
whether the promise is fulfilled or rejected, you use thefinally()
method
The entire code will be :
const doSomething = ()=>{
// let run some task here
}
const getSomething = ()=> {
return new Promise((resolve,reject)=> {
// perform some async operation here...
let success = false //async operation was unsuccessful
if (success) {
resolve("We got some data back");
} else {
reject("Opps Error fetching data");
}
})
}
//get the value of the promise object using then()
getSomething().then(
(result)=> {
/* handle a successful result */
console.log(result)
}
).catch((error)=>{
/*handle an unsuccessful task */
console.log(error)
}).finally(()=>{
//finally, run this function
doSomething()
})
Summary
- We can define Promise, as an object that is used as a placeholder for the future result of an asynchronous operation
- A promise begins in the
Pending
state and ends in eitherfulfilled
orrejected
state. - Utilize the
then()
method to arrange a callback to be executed when the promise is fulfilled, andcatch()
method to handle a callback to be executed when the promise is rejected. - Place the task to be execute in the finally() method whether the promise is fulfilled or rejected.
If you have found value in this article, kindly share on your social media platform.
Do you need some clarification or you have a suggestion? Feel free to post your comment, I would love to read from you.
Don't forget to follow me on Twitter