Understanding JavaScript Promises

Naga

Naga

July 27, 2024

What is a Promise?

A promise in JavaScript is an object that represents the eventual completion (or failure) of an asynchronous operation and its resulting value. A promise can be in one of three states:

Creating a Promise

You can create a promise using the Promise constructor, which takes a function (executor) with two arguments: resolve and reject. These arguments are themselves functions used to determine the outcome of the promise.

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

  if (success) {
    resolve("The operation was successful!");
  } else {
    reject("The operation failed.");
  }
});


Consuming Promises

To handle the result of a promise, you use the then method for fulfilled promises and the catch method for rejected promises.

myPromise
  .then((message) => {
    console.log(message); // "The operation was successful!"
  })
  .catch((error) => {
    console.error(error); // "The operation failed."
  });


You can also chain multiple then methods to handle subsequent operations:

myPromise
  .then((message) => {
    console.log(message);
    return "Another success message!";
  })
  .then((newMessage) => {
    console.log(newMessage); // "Another success message!"
  })
  .catch((error) => {
    console.error(error);
  });


Promise Chaining

One of the most powerful features of promises is the ability to chain them. This is useful for executing multiple asynchronous operations in sequence.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("First promise resolved!"), 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Second promise resolved!"), 2000);
});

promise1
  .then((result) => {
    console.log(result);
    return promise2;
  })
  .then((result) => {
    console.log(result);
  });

Handling Multiple Promises

When you need to wait for multiple promises to complete, you can use Promise.all or Promise.race.

Promise.all([promise1, promise2])
  .then((results) => {
    console.log(results); // ["First promise resolved!", "Second promise resolved!"]
  })
  .catch((error) => {
    console.error(error);
  });


Promise.race([promise1, promise2])
  .then((result) => {
    console.log(result); // "First promise resolved!" (since it resolves faster)
  })
  .catch((error) => {
    console.error(error);
  });


Common Use Cases

  1. Fetching Data: Promises are commonly used with fetch API to handle HTTP requests.
fetch("https://api.example.com/data")
  .then((response) => response.json())
  .then((data) => {
    console.log(data);
  })
  .catch((error) => {
    console.error("Error fetching data:", error);
  });


  1. Delaying Execution: Using promises with setTimeout to delay operations.
function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

delay(2000)
  .then(() => {
    console.log("Executed after 2 seconds");
  });


Conclusion

Promises are a fundamental part of modern JavaScript, enabling better handling of asynchronous operations with a cleaner, more readable code structure. By understanding how to create, consume, and chain promises, you can write more efficient and manageable asynchronous code. Whether you're fetching data from an API, performing complex sequences of asynchronous tasks, or handling multiple asynchronous operations concurrently, promises provide a robust tool to manage these scenarios effectively