Explained: All You Need to Know About JavaScript Promises
Have your parents ever promised to buy you the things you wished for?
Before you start reading this, here are some prerequisites you need to know:
- Basics of JavaScript
- Classes in JavaScript
- Modules in JavaScript
What is an asynchronous operation in JavaScript?
Asynchronous operation refers to an operation that allows a computer to continue executing other code while waiting for asynchronous operations to complete. With that being said, we can save our time by using an asynchronous approach and prevent our programs from coming to a halt.
A real-life example of the asynchronous operation is when your robot is helping you to do your house chores; you’re free to do anything you want in the meantime.
The same goes for computers. We use an asynchronous approach in programming too. For example, operations like making a network request to a database can be tedious and super time consuming but JavaScript has the power to execute other tasks while awaiting its completion.
Let’s dive into modern JavaScript that handles asynchronous operations using Promise
.
Macrotasks in JavaScript
Before understanding Promise in JavaScript, you should understand macrotasks first. Macrotasks enable developers to perform tasks asynchronously in a synchronous way. There are a few macrotasks in JavaScript. For example, setInterval
, setImmediate
, and setTimeout
.
But I will only go through setTimeout
for the sake of this article. So, what exactly in the world does setTimeout
do? setTimeout
is a Node API (also known as web API) that orders tasks to be performed after a delay. setTimeout
takes in a callback function and how many milliseconds you want it to delay.
For example:
- From the example above, we will complete the synchronous operation first which is
console.log(“I am first”);
which will push to the stack and print to the console.
- Follow by
console.log(“I am second”);
.
- Then when it comes to
useMacro
turn,useMacro
will only execute after 1 second. This delay is performed asynchronously. This means that our program will not halt suddenly during the delay. It’s still running but it is now inside a queue. I will explain more about the queue in the picture below. Just in case you need some Math help:
setTimeout( )
will get pushed to the stack once it is empty and the callback function will get pushed to the Web API for processing.
- Web API will send the callback into the queue and wait for completion.
- The callback function inside the queue will then get pushed into the stack after 1 second and logged
I am third
to the console.
- In asynchronous JavaScript, there is one thing called event-loop. Event-loop’s job is to act as a middleman between queue and stack; if there’s nothing in the stack then code in the queue will get pushed to the stack and start executing.
- Before
useMacro
can run, the synchronous code will run first. Finally, after all the synchronous code,useMacro
will run and returnI am third
to the console. - And this is what we will get in the final result:
So, what is a Promise?
A Promise is an object that represents the future outcome (success or fail) of an asynchronous operation.
A Promise consist of three states:
- Pending: Initial state of the operation that has yet to be completed.
- Fulfilled: Operation has completed successfully and the Promise has a resolved value.
- Rejected: Operation has failed and the Promise has a reason for failure. Usually will result in an
Error
.
An example of a real-life example of a Promise:
From the picture above, a Promise initial state would always be in pending mode. If it is resolved then it will have a resolved value, else if it is rejected it would have an Error
for why it failed.
What does a Promise object look like?
We use the new
keyword and Promise
constructor method in order to create a new Promise
object.
- First, we will make a function which also known as the executor function. From the above example,
anyFunction
is our executor function. - The executor function will be receiving two functions as parameters that will dictate the future outcome.
resolve
andreject
are two functions as parameters.- If
specifyYourConditionHere
is true, thenresolve( )
code will run and return‘I resolved!’
. Then it will alter the Promise’s status from pending to fulfilled. - Else
reject( )
code will run and return‘I rejected!’
. Then it will alter the Promise's status from pending to rejected. - The
Promise
constructor takes in a function parameter which is the executor function and starts to run the code asynchronously. The result will either be resolved or rejected.
How to use a Promise?
As the Promise
's initial state would always be in pending mode, the Promise will always have a future outcome either fulfilled or rejected.
But have you asked yourself what can I do after it has finished running the Promise
?
We can use .then( )
to follow up on another action. This method always returns a Promise
.
From the example above,
- If a
pending promise
get a result ofresolve
which means fulfilled, then the project is done. - If a
pending promise
get a result ofreject
which means rejected, then it will start slacking off.
For your information, .then( )
is a higher-order function that takes two arguments to represent the callback functions. The two arguments are called handlers.
What are the two handlers?
- The first handler which is known as the success handler,
onFulfilled
. It should contain logic that indicates the Promise is resolved. - The second handler which is known as the failure handler,
onRejected
. It should contain logic that indicates the Promise is rejected.
How do you use success/failure handlers as callback functions?
To handle a success or failure Promise when it is resolved or rejected, we can pass the success and failure handler into a callback function, then invoke it with .then( )
as in the following:
From the example above:
work
is a Promise that with a conditional statement checks if it is resolved then it will return a resolved value which isWorking on side projects
else return a rejected value which isUnclear what to do
.- Then we will define a function which are
success( )
andfailure( )
. Then we will print the argument that passed into it. - Next, we invoke
work
with.then( )
, passing insuccess( )
andfailure( )
function. - As you might know already, it will get resolved and return a value then logged to the console which is
Working on side projects
.
Why don’t you follow the rule of Separation of Concerns (SoC)?
Above are just the beginning, to follow the rule of Separation of Concerns (SoC), this is where .catch( )
function comes into play.
This function will only take in one argument which is onRejected
and return the reason for rejection. .catch( )
achieve the same thing as .then( )
but it is only used to catch the Error
.
For example:
In the picture, there is a code snippet on using .catch( )
. Since reject
is true then we will return Unclear what to do
as a reason for rejection.
By implementing SoC, we are able to improve our code readability and making it easier for debugging when a particular part of our code gone wrong.
How to use Promise.all( ) ?
What if you have a ton of Promises? Will you wait for all the Promises to get resolve one by one? That is where Promise.all( )
comes in.
Promise.all( )
accepts an array of Promises and returns only one Promise.
- If every Promise in the array gets resolved, then
Promise.all( )
will return a Promise containing a resolved value. - If a single Promise inside an array rejected, the following Promises awaiting resolving will also be rejected which is also known as failing fast, then
Promise.all( )
will return a Promise containing the reason for the rejection.
For example:
- From the above, we have three Promises that are waiting for completion.
- Secondly, we use success and failure handlers as callback functions.
- We then create a variable which stored
Promise.all( )
. Promise.all( )
will determine the three Promises whether it is rejected or resolved.- Lastly, we invoke the variable,
myPromises
with.then( )
to return the resolved value and.catch( )
reason for rejection. - Since one Promise got rejected which is
example3
, then.catch( )
will do its job to catch the reason for rejection which isFailed: I rejected!
.
Conclusion
That all for Promises in JavaScript. Remember, a Promise is something that will either resolve or reject — it will always be in pending mode. Have you learned anything from this article? I hope you have found this article useful, thank you for reading.
Get connected with me via LinkedIn and Twitter.
More content at plainenglish.io