Published: 16th May, 2024
Author: Sohan Shashikumar
Read Time: 5 minutes
A promise is a special kind of object that determines the eventual completion/failure of an asynchronous operation.
A promise is created by using the Promise()
constructor. It
takes a function as an argument, called the executor
. The
executor in-turn has access to two methods, resolve
and
reject
which are called to mark the success or failure of an
async operation respectively.
Lots of talk, lets jump into the code!
const myPromise = new Promise((resolve, reject) => {
console.log('Hello World');
});
Hello World
to the console when executed.
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
// this function executes after 2 seconds
const data = {
name: 'sohan',
age: 21
};
resolve(data);
}, 2000);
});
In the executor, we are using a setTimeout
which is built
into JavaScript, that executes a function after a specific delay. After 2 seconds, we are
creating a data object with the name
and
age
property. Notice that we are calling the
resolve
method. Try running this code.
Nothing happens!
This is because we are not handling what happens after the promise has been fulfilled/successful. A promise object provides three special methods to handle the outcome of a promise.
then()
: Used to handle successful operations.
catch()
: Used to handle failed operations.
finally()
: Used to perform any cleanup operations
regardless of the outcome.
lets make some modifications to the above code.
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
// this function executes after 2 seconds
const data = {
name: 'sohan',
age: 21
};
resolve(data);
}, 2000);
});
myPromise.then((response) => {
console.log(response);
});
We are attaching a .then()
to the created promise that takes
a callback function which gets called after the promise resolves i.e when
resolve()
is called. We also have access to the response
which is basically the data
object that is passed to
resolve
in the executor, received after 2 seconds.
It is important to note that the value with which
resolve()
is called with is available in the callback passed
to .then()
Try running this code, you will see the data object we created, logged to the console after 2 seconds
Let's make a slight modification to the existing code.
console.log('start');
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
// this function executes after 2 seconds
const data = {
name: 'sohan',
age: 21
};
resolve(data);
}, 2000);
});
myPromise.then((data) => {
console.log(data);
});
console.log('end');
Take a pause to guess the outcome of the code!
start
end
{ name: "sohan", age: 21 }
Congrats to those who got it right 🍻 Don't worry if you didn't, let's break it down line by line!
On line 1, we are simply logging start
to the console. Then
we are creating a promise object and passing it an executor. The executor runs, schedules a
setTimeout
that needs to run after 2 seconds.
We attach a .then()
callback and pass it a function that
needs to execute after the promise is fulfilled i.e after 2 seconds.
The control goes to the next line and logs end
. Notice how it
does not wait for those 2 seconds to elapse before logging
end
? That is how its being asynchronous. It does not block
the main thread.
console.log('start');
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((response) => response.json())
.then((json) => console.log(json));
console.log('end');
Here, we are actually performing a network request to load some data. We are using the
JavaScript native fetch()
API. The call to
fetch()
returns a Promise which means we can use
.then()
.catch()
and
.finally()
Think of it like a step by step process of receiving the outcome. Take a pause to guess the outcome, yet again
start
end
{
"userId": 1,
"title": "delectus aut autem"
}
hmmmmm Pretty strange? Why? We aren't setting a timeout but yet our result is being logged at the end. That's because, in the real world, network requests take time and we cannot determine how long it would take for the data to be fetched.
If there is a serious issue at the server's end, our code will keep waiting forever. We do not want to write code like this in a production environment. This is exactly what promises do.
Let's modify the above code
console.log('start');
fetch('https://supersecretwebsitethatdoesnotexist.com/data')
.then((response) => response.json())
.then((json) => console.log(json))
.catch((err) => console.log(`Whoops! Something went wrong`, err));
console.log('end');
It's always good to handle errors as it will help your users know if something went wrong instead of infinite loading screens. You as the developer will also understand what went wrong through your application support tickets.
In the code above, we are making a request to a url that does not exist. Try running it. We'll
run into an error. Notice how we are also handing it? This is done using the
.catch()
block. Here you can write code to get notified about
it or send it to an error logging service like datadog or sentry.
Promise()
.then()
,
.catch()
and
.finally()
which are used to consume, handle errors and
perform cleanup operations respectively.
.then()
also returns a promise, meaning they can be
chained.
Your feedback is highly appreciated and will be used to improve the quality of existing & future posts!
What do you rate this post?