Wtf is Promises and why it slaps?đ


Do you remember how you were so excited to learn JavaScript, especially that initial topics like loops and functions and suddenly they started teaching you callback hell, promises and async/await and you sat there likeâŚ.woah what??!!! Wait i canât understand?? Yeah we all have been through that.
Let me explain. But before that donât look at this post and be like âWhy would i listen to you?â (Did you read that in meme style?). Honestly your question is not wrong, why would yo listen to me? Honestly idk man i mean you have probably watched millions of tutorials and you still didnât understand so whatâs the harm in one more.
Before that letâs review Callback hell(no bs style)
Callbacks - Functions that are passed as arguments to another function.
Why use callbacks? - To handle asynchronous tasks.
Callback hell - Too many nested callbacks inside each other creating a pyramid of doom, your code becomes hard to read and understand.(and debug)
Why it happens? When you are trying to handle multiple async tasks.
What is async tasks - tasks that are not directly handled by JS main thread.(cause JS is single threaded - does task one at a time(this in English is known as synchronous) but when JS throws tasks that require a lot of time(fetching data, reading files, or waiting for timers) to web APIs these tasks becomes Asynchronous))
Promises:-
What do you mean by Promises in english? When i say âI promise to return your book tomorrowâ, there are three possibilities:-
I will give you your book in the future(Yay!)
I didnât gave you your book :(
Itâs still today
This is exactly what promises is in JS. It is an object that represents a task that will be completed in future. Based on the example i gave Promises in JS also have 3 states:-
Resolved(fulfilled) - Promise has been successfully completed
Reject - Something went wrong
Pending - The promise is still waiting for a resolution.
Thatâs it babe, letâs look at the syntax:-
let myPromise = new Promise((res, rej) => { //res stands for resolve and rej for reject
let success = True; // let's suppose i gave you the book
if(success) {
res("Task completed"); //Promise resolved yay
} else {
rej("Task rejected"); //promise rejected noooo
}
});
myPromise.then((message) => //if resolved .then() will run
console.log(message))
.catch((error) => //if reject .catch() will run
console.log(error));
Letâs look at an example, I am Simulating a Delayed Task ( using setTimeout)
function delayTask() {
return new Promise((res) => {
setTimeout(() => {
resolve("Task done after 2 seconds!");
}, 2000);
});
}
// Using the promise
delayTask().then((message) => console.log(message));
Output after 2 sec - Task done after 2 seconds!.
How it works?
The Promise starts, but JavaScript does not wait(non-blocking nature of JS cause itâs single threaded).
After 2 sec, res() runs, and .then() prints the message.
Let me give you one more example that my teacher gave (shout out to him) - Fetching Data (we are Simulating an API Call)
function getUserData() {
return new Promise((res, rej) => {
console.log("Fetching user data...");
setTimeout(() => {
let success = true; // Simulate success
if (success) {
resolve({ name: "Anika", age: 21 });
} else {
reject("Failed to fetch user data!");
}
}, 3000);
});
}
// Using the promise
getUserData()
.then((user) => console.log("User data:", user))
.catch((error) => console.log(error));
âOkay thatâs interesting but why do i wanna use it?â Good question dude letâs first understand one more topic which is Promise chaining.
Sometimes, we need to run multiple asynchronous task one after another, where each task depends on the previous one. Promise chaining allows us to connect multiple .then() methods so each one runs after the previous promise resolves.
function step(time, message) {
return new Promise((res => { //only using res because its highly unlikely that the timer will reject something
setTimeout(() => {
console.log(message);
res();
}, time);
});
}
step(1000, "Step 1") //
.then(() => step(1000, "Step 2"))
.then(() => step(1000, "Step 3"))
.then(() => step(1000, "Step 4")); //since i didn't wrote rej i am not writing .catch
Now if i want to write this same code using callbacks it would look like this:-
setTimeout(() => {
console.log("Step 1");
setTimeout(() => {
console.log("Step 2");
setTimeout(() => {
console.log("Step 3");
setTimeout(() => {
console.log("Step 4");
}, 1000);
}, 1000);
}, 1000);
}, 1000); //This is what callback hell looks like, i really hope you are not tearing up by reading this
In promise chaining we donât use multiple .catch() - one is placed at the end of the chain to catch errors from any step. If you want, you can add individual .catch() after each .then() for step-specific error handling.
function getUser() {
return new Promise((res) => {
setTimeout(() => {
console.log("User data fetched!");
res({ id: 1, name: "Anika" });
}, 1000);
});
}
function getPosts(user) {
return new Promise((res, rej) => { // Adding reject case
setTimeout(() => {
console.log(`Failed to fetch posts!`);
rej("Error: Could not fetch posts");
}, 1000);
});
}
function getComments(posts) {
return new Promise((res) => {
setTimeout(() => {
console.log("Comments on posts fetched!");
res(["Comment A", "Comment B"]);
}, 1000);
});
}
getUser()
.then(getPosts)
.then(getComments)
.then((comments) => console.log("Final Data:", comments))
.catch((error) => console.log("Error caught:", error)); // Handle errors
What about .finally?
Its a method that runs after a promise is settled, it dosenât care if the promise was resolved or rejected.
Why use it? To clean up resources (like closing a loading spinner or resetting UI)
Syntax:-
promise
.then((res) => console.log("Success:", result))
.catch((error) => console.log("Error:", error))
.finally(() => console.log("Cleanup done!")); //does not receive any arguments
Now you might be wandering âHmm then Promises are the GOATâ well not exactly.
Promises are harder to manage. How?
fetchData() .then((data) => { return processData(data); }) .then((processedData) => { return saveData(processedData); }) .then((result) => { console.log("Data saved:", result); }) .catch((error) => { console.log("Error:", error); }); //Each .then adds another layer => If the code has lot of steps it becomes harder to read, debug and maintain
So we usually go for another topic called async/await, but thatâs a topic for another day.
I hope this article made Promises atleast 1% easy. Till then keep coding and keep vibing.
Subscribe to my newsletter
Read articles from Namrata Thakur directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
