JavaScript Promises

JavaScript Promises are a powerful tool for managing asynchronous operations. They simplify the process of handling tasks like API calls, file operations, or timers by providing a cleaner and more readable alternative to callback-based code.

What is a Promise?

A Promise is an object that represents the eventual completion (or failure) of an asynchronous operation. It has three states:

  1. Pending: The operation has not yet completed.
  2. Fulfilled: The operation completed successfully, and the promise has a result.
  3. Rejected: The operation failed, and the promise contains an error.

Creating a Promise

A Promise is created using the Promise constructor, which takes a function with two arguments: resolve and reject.

Example:

const myPromise = new Promise((resolve, reject) => {
    let success = true;

    if (success) {
        resolve("Operation successful!");
    } else {
        reject("Operation failed!");
    }
});

myPromise
    .then((result) => console.log(result)) // Output: "Operation successful!"
    .catch((error) => console.error(error));

In this example:

  • resolve is called when the operation succeeds.
  • reject is called when the operation fails.

Using Promises

The .then() Method

The then() method runs when the promise is resolved (fulfilled).

fetch("https://api.example.com/data")
    .then((response) => response.json())
    .then((data) => console.log(data))
    .catch((error) => console.error("Error:", error));

The .catch() Method

The catch() method handles errors or rejections.

The .finally() Method

The finally() method runs after the promise settles, regardless of whether it was fulfilled or rejected.

myPromise
    .then((result) => console.log(result))
    .catch((error) => console.error(error))
    .finally(() => console.log("Promise completed."));

Chaining Promises

Promises can be chained to handle a sequence of asynchronous tasks.

Example:

fetch("https://api.example.com/user")
    .then((response) => response.json())
    .then((user) => fetch(`https://api.example.com/orders/${user.id}`))
    .then((response) => response.json())
    .then((orders) => console.log(orders))
    .catch((error) => console.error("Error:", error));

Handling Multiple Promises

JavaScript provides methods like Promise.all(), Promise.allSettled(), Promise.any(), and Promise.race() for working with multiple promises.

Promise.all()

Waits for all promises to fulfill or for one to reject.

const promise1 = Promise.resolve("Promise 1");
const promise2 = Promise.resolve("Promise 2");

Promise.all([promise1, promise2])
    .then((results) => console.log(results)) // Output: ["Promise 1", "Promise 2"]
    .catch((error) => console.error(error));

Promise.race()

Resolves or rejects as soon as the first promise settles.

Async/Await: A Modern Approach

While Promises improve readability, the async/await syntax introduced in ES2017 makes working with promises even cleaner.

Example:

async function fetchData() {
    try {
        const response = await fetch("https://api.example.com/data");
        const data = await response.json();
        console.log(data);
    } catch (error) {
        console.error("Error:", error);
    }
}

fetchData();

Common Mistakes with Promises

  1. Forgetting to Return Promises:
    • Always return promises in .then() to avoid unexpected results.
  2. Not Handling Errors:
    • Use .catch() or try-catch blocks to handle errors.
  3. Nesting Promises:
    • Avoid nesting by chaining .then() or using async/await.

Conclusion

Promises are a cornerstone of modern JavaScript, enabling efficient and readable asynchronous programming. Combined with async/await, they provide a robust way to handle complex workflows. Explore more tutorials and resources at The Coding College.

Leave a Comment