A Deeper Dive into JavaScript Promises

Touseef Khan
4 min readAug 11, 2024

JavaScript can sometimes be confusing, especially when dealing with tasks that take time to complete, like fetching data from an API. This is where promises come in handy. In this blog, we’ll break down what promises are and how you can use them, using straightforward examples that anyone can grasp.

What is a Promise?

A promise in JavaScript is like a commitment to do something in the future. Imagine you order a package online. The store promises to deliver it to you, but it may take some time. In JavaScript, a promise is an object that represents the eventual outcome (success or failure) of an asynchronous operation.

A promise can be in one of three states:
1. Pending: The initial state — when the outcome is still unknown.
2. Fulfilled: The operation was successful.
3. Rejected: The operation failed.

Creating a Simple Promise

Let’s create a basic promise to illustrate how it works. Here’s an example:

let myPromise = new Promise((resolve, reject) => {
let operationSuccessful = true; //You can set it to false for failiure case
if (operationSuccessful) {
resolve("Operation was successful!");
} else {
reject("Operation failed.");
}
});

In this code, we define a promise called myPromise. Inside the promise, there’s a function that takes two arguments: resolve and reject. These arguments are also functions:

- resolve: You call this when the operation is successful.
- reject: You call this when something goes wrong.

Using a Promise

Now that we have our promise, let’s see how to use it. We can handle the success and error cases using .then() and .catch().

myPromise
.then((message) => {
console.log(message); // This will run if the promise is resolved
})
.catch((error) => {
console.log(error); // This will run if the promise is rejected
});

If operationSuccessful is true, the promise resolves, and “Operation was successful!” is logged to the console. If it’s false, the promise is rejected, and “Operation failed.” is logged instead.

A Real-World Example: Fetching Data

Let’s look at a more practical example. Suppose you’re fetching data from an external source. This is an asynchronous operation, and a promise can help you handle it:

function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
let data = "Data retrieved successfully!";
resolve(data); /* You can change this to reject("Failed to retrieve data.")
to simulate an error */

}, 2000);
});
}

//Call the function
fetchData()
.then((data) => {
console.log(data); // This runs if the data is fetched successfully
})
.catch((error) => {
console.log(error); // This runs if there was an error fetching the data
});

In this example, fetchData returns a promise. We simulate fetching data by using setTimeout to delay the operation for 2 seconds. If the promise resolves, you’ll see “Data retrieved successfully!” in the console. If it’s rejected, you’ll see an error message.

Why Use Promises?

Promises make your code cleaner and easier to manage, especially when dealing with multiple asynchronous tasks. Without promises, you might end up with deeply nested callbacks, commonly known as “callback hell.”

Here’s a comparison:

Without Promises:

function loginUser(username, password, callback) {
setTimeout(() => {
console.log("User logged in");
callback({ userId: 1 });
}, 1000);
}

function fetchUserData(userId, callback) {
setTimeout(() => {
console.log("User data fetched");
callback({ userId: 1, name: "John Doe" });
}, 1000);
}

function displayUserData(userData) {
setTimeout(() => {
console.log("User name is: " + userData.name);
}, 1000);
}

loginUser("john", "password123", (user) => {
fetchUserData(user.userId, (userData) => {
displayUserData(userData);
});
});

With Promises:

function loginUser(username, password) {
return new Promise((resolve) => {
setTimeout(() => {
console.log("User logged in");
resolve({ userId: 1 });
}, 1000);
});
}

function fetchUserData(userId) {
return new Promise((resolve) => {
setTimeout(() => {
console.log("User data fetched");
resolve({ userId: 1, name: "John Doe" });
}, 1000);
});
}

function displayUserData(userData) {
return new Promise((resolve) => {
setTimeout(() => {
console.log("User name is: " + userData.name);
resolve();
}, 1000);
});
}

loginUser("john", "password123")
.then((user) => fetchUserData(user.userId))
.then((userData) => displayUserData(userData))
.then(() => console.log("All tasks completed"));

In the promise-based version, each function returns a promise, allowing you to chain the operations together with .then(). This makes the code more readable and easier to maintain. You can clearly see the sequence of operations, and there’s no deep nesting

Conclusion

Promises are a fundamental part of modern JavaScript, helping you manage asynchronous operations in a clear and efficient way. By understanding the basics of promises, you can write code that’s easier to read, maintain, and debug.

I hope this blog helps you better understand this essential JavaScript feature. If you have any questions or need further clarification, feel free to reach out to me at touseefkhan4pk@gmail.com. I’m happy to help!

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Touseef Khan
Touseef Khan

Written by Touseef Khan

Experienced full-stack developer proficient in Java, AEM, & .NET. Let's connect: https://www.linkedin.com/in/touseef-khan-19214930/

No responses yet

Write a response