Programming Language
JavaScript
Synchronous and Asynchronous
Promise

Understanding Promises in JavaScript

In JavaScript, promises are a powerful way to handle asynchronous operations. A promise represents the eventual completion (or failure) of an asynchronous task and its resulting value. This article will explain what promises are, how they work, and how you can manage multiple promises effectively.

What is a Promise?

A promise is an object in JavaScript that represents the result of an asynchronous operation. It can be in one of three states:

  1. Pending: The initial state; the promise has not yet been fulfilled or rejected.
  2. Fulfilled: The operation completed successfully, and the promise has a result.
  3. Rejected: The operation failed, and the promise has a reason for the failure.

How Promises Work

When you create a promise, you provide it with a function that contains the asynchronous code. This function receives two arguments: resolve and reject.

  • resolve: Call this function when the asynchronous operation is successful. It passes the result to the promise.
  • reject: Call this function when the asynchronous operation fails. It passes an error message to the promise.

Example

// Creating a new Promise object
const myPromise = new Promise((resolve, reject) => {
  // Simulate a successful asynchronous operation after 3 seconds
  setTimeout(() => {
    resolve('Promise completed'); // This will call resolve() with the message 'Promise completed'
  }, 3000);
  
  // Simulate a failed asynchronous operation after 2 seconds
  setTimeout(() => {
    reject('Promise failed'); // This will call reject() with the message 'Promise failed'
  }, 2000);
});
 
// Log message to indicate the start of promise execution
console.log('Promise start');
 
// Log the Promise object itself to see its state
console.log(myPromise);
 
// Log message to indicate that promise is in progress
console.log('Promise in progress');
 
// Handle the result of the promise
myPromise
  .then((value) => {
    // This block will be executed if the promise is resolved successfully
    console.log(value); // 'Promise completed' will be logged if resolve() is called
  })
  .catch((error) => {
    // This block will be executed if the promise is rejected
    console.log(error); // 'Promise failed' will be logged if reject() is called
  });

In this example:

myPromise is created with a function that simulates an asynchronous task using setTimeout. If the task is successful, it calls resolve with a success message. If the task fails, it calls reject with an error message. The .then() method handles the success case, and .catch() handles the failure case.

Handling Multiple Promises

JavaScript provides several methods to handle multiple promises at once. These methods help you manage complex asynchronous operations and improve code readability.

Promise.all()

Promise.all() takes an array of promises and returns a single promise that resolves when all the promises in the array have resolved. If any promise in the array is rejected, the returned promise will be rejected with that error.

const promise1 = Promise.resolve('First promise resolved');
const promise2 = Promise.resolve('Second promise resolved');
const promise3 = Promise.resolve('Third promise resolved');
 
Promise.all([promise1, promise2, promise3])
  .then((results) => {
    console.log(results); // ['First promise resolved', 'Second promise resolved', 'Third promise resolved']
  })
  .catch((error) => {
    console.error('One of the promises failed:', error);
  });

Promise.race()

Promise.race() takes an array of promises and returns a promise that resolves or rejects as soon as the first promise in the array resolves or rejects. The result or error of the first promise will be passed to the returned promise.

const promise1 = new Promise((resolve) => setTimeout(resolve, 1000, 'First promise resolved'));
const promise2 = new Promise((resolve) => setTimeout(resolve, 500, 'Second promise resolved'));
 
Promise.race([promise1, promise2])
  .then((result) => {
    console.log(result); // 'Second promise resolved'
  })
  .catch((error) => {
    console.error('Race error:', error);
  });

Promise.any()

Promise.any() takes an array of promises and returns a single promise that resolves when the first promise in the array resolves. If all the promises are rejected, it returns a promise that is rejected with an AggregateError, which contains all the rejection reasons.

const promise1 = Promise.reject('First promise rejected');
const promise2 = Promise.reject('Second promise rejected');
const promise3 = Promise.resolve('Third promise resolved');
 
Promise.any([promise1, promise2, promise3])
  .then((result) => {
    console.log(result); // 'Third promise resolved'
  })
  .catch((error) => {
    console.error('All promises rejected:', error);
  });

Promise.allSettled()

Promise.allSettled() takes an array of promises and returns a single promise that resolves after all of the given promises have either resolved or rejected. It returns an array of objects that describe the outcome of each promise.

const promise1 = Promise.resolve('First promise resolved');
const promise2 = Promise.reject('Second promise rejected');
const promise3 = Promise.resolve('Third promise resolved');
 
Promise.allSettled([promise1, promise2, promise3])
  .then((results) => {
    console.log(results);
    /*
    [
      { status: 'fulfilled', value: 'First promise resolved' },
      { status: 'rejected', reason: 'Second promise rejected' },
      { status: 'fulfilled', value: 'Third promise resolved' }
    ]
    */
  });

Conclusion

Promises are a key feature in JavaScript for handling asynchronous operations. They provide a way to work with asynchronous tasks in a more manageable and readable manner. By using methods like Promise.all(), Promise.race(), Promise.any(), and Promise.allSettled(), you can efficiently handle multiple asynchronous operations and ensure your code remains clean and effective.