• The Frontend Feed
  • Posts
  • Mastering the Promise API: A Guide to All 6 Static Methods in JavaScript

Mastering the Promise API: A Guide to All 6 Static Methods in JavaScript

Understanding JavaScript promises is key to mastering asynchronous programming, which is crucial for both real-world applications and technical interviews. The Promise API provides several static methods that give developers powerful tools for managing multiple promises and handling various asynchronous operations efficiently. Whether you’re preparing for a technical interview or building complex applications, knowing how to use these six static methods—Promise.all, Promise.allSettled, Promise.race, Promise.any, Promise.resolve, and Promise.reject—is essential.

If you’re new to promises or need a refresher, be sure to check out our comprehensive JavaScript Promises Guide to get a solid foundation before diving into these advanced concepts.

Mastering the Promise API: A Guide to All 6 Static Methods in JavaScript

In this guide, we’ll explore each of these methods in detail, including how they work, when to use them, and how they can help you write cleaner, more effective code.

1. Promise.all:

The Promise.all method takes an array (or any iterable) of promises and returns a single promise that resolves when all of the promises have resolved or rejects as soon as one of the promises rejects. If any of the items in the array are not promises, they are treated as resolved promises with their values.

Use Case:

• Ideal when you need to wait for multiple asynchronous operations to complete before proceeding, such as fetching data from multiple APIs or performing concurrent calculations.

const promise1 = Promise.resolve(3);
const promise2 = 42;  // Non-promise value
const promise3 = new Promise((resolve) => {
  setTimeout(resolve, 100, 'foo');
});

// Non-promise values, like 42 in this example, are treated as if they were resolved promises: Promise.resolve(42).
Promise.all([promise1, promise2, promise3]).then(values => {
  console.log(values); // [3, 42, 'foo']
});


const promise4 = Promise.reject('Error occurred');

// If any promise rejects (like promise4), the entire Promise.all will reject with that reason, and the .catch() block will handle the error.
Promise.all([promise1, promise2, promise3, promise4])
  .then(values => {
    console.log(values); // This won't execute because of the rejection
  })
  .catch(error => {
    console.error(error); // 'Error occurred'
  });

Note: If any promise rejects (like promise4), the entire Promise.all will reject with that reason, and the .catch() block will handle the error.

2. Promise.allSettled:

Promise.allSettled returns a promise that resolves after all of the given promises have either resolved or rejected, with an array of objects describing the outcome of each promise. Similar to Promise.all, non-promise values are treated as resolved promises.

 Use Case:

• Useful when you want to know the outcome of all promises, regardless of whether they succeed or fail, such as logging the results of multiple operations without stopping on errors.

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'Error occurred'));
const promise3 = 'non-promise value';  // Non-promise value

Promise.allSettled([promise1, promise2, promise3])
  .then(results => {
    results.forEach(result => {
      console.log(`${result.status}: ${result.value || result.reason}`);
    });
  });
// Logs:
// 'fulfilled: 3'
// 'rejected: Error occurred'
// 'fulfilled: non-promise value'

Note: Even if one or more promises are rejected, Promise.allSettled still resolves, allowing you to handle each result individually.

3. Promise.race:

Promise.race returns a promise that resolves or rejects as soon as one of the promises resolves or rejects. Non-promise values are treated as immediately resolved promises.

Use Case:

• Ideal for scenarios where you want to take action as soon as the fastest promise completes, such as setting timeouts for requests or implementing a fallback strategy.

const promise1 = new Promise((resolve) => setTimeout(resolve, 500, 'one'));
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'two'));

Promise.race([promise1, promise2])
  .then(value => {
    console.log(value); // 'two' (because promise2 resolves first)
  })
  .catch(error => {
    console.error(error); // This won't execute because a promise resolves first
  });


const promise3 = new Promise((resolve) => setTimeout(resolve, 500, 'one'));
const promise4 = new Promise((_, reject) => setTimeout(reject, 100, 'Error occurred'));

Promise.race([promise3, promise4])
  .then(value => {
    console.log(value); // This won't execute because the rejection happens first
  })
  .catch(error => {
    console.error(error); // 'Error occurred'
  });

Note: In Promise.race, the first promise to settle (resolve or reject) determines the outcome.

4. Promise.any:

Promise.any returns a promise that resolves as soon as one of the promises resolves. If all promises are rejected, it rejects with an AggregateError. Non-promise values are treated as resolved promises.

Use Case:

• Useful when you need the first successful result from multiple operations, like querying multiple APIs and using the first successful response.

const promise1 = Promise.reject('Error 1');
const promise2 = Promise.reject('Error 2');
const promise3 = Promise.resolve('Success');

Promise.any([promise1, promise2, promise3])
  .then(value => {
    console.log(value); // 'Success'
  })
  .catch(error => {
    console.error(error.errors); // This won't execute because there's a successful promise
  });

const promise4 = Promise.reject('Error 1');
const promise5 = Promise.reject('Error 2');
const promise6 = Promise.reject('Error 3');

Promise.any([promise4, promise5, promise6])
  .then(value => {
    console.log(value); // This won't execute because all promises reject
  })
  .catch(error => {
    console.error(error.errors); // ['Error 1', 'Error 2', 'Error 3']
  });

Note: If all promises reject, Promise.any will throw an AggregateError containing all rejection reasons.

5. Promise.resolve:

Promise.resolve returns a promise that is resolved with a given value. If the value is a promise, it simply returns that promise. If the value is not a promise, it creates a promise that is resolved with that value.

Use Case:

• Often used to ensure that a value is treated as a promise, useful for standardizing code or converting non-promise values into a promise context.

Promise.resolve('foo')
  .then(value => {
    console.log(value); // 'foo'
  })
  .catch(error => {
    console.error(error); // This won't execute
  });

const promise = Promise.resolve(new Promise((resolve) => {
  resolve('bar');
}));
promise.then(value => {
  console.log(value); // 'bar'
});

Note: Promise.resolve never rejects. If you pass in a promise that rejects, the rejection will happen in the original promise, not in the Promise.resolve.

6. Promise.reject:

Promise.reject returns a promise that is rejected with a given reason, regardless of whether the reason is a promise or not.

Use Case:

• Useful for returning an immediately rejected promise in testing or simulating error conditions.

Promise.reject(new Error('Something went wrong'))
  .catch(error => {
    console.error(error); // Error: Something went wrong
  });

const rejectedPromise = Promise.reject('simple rejection');
rejectedPromise
  .then(value => {
    console.log(value); // This won't execute
  })
  .catch(reason => {
    console.error(reason); // 'simple rejection'
  });

Note: Promise.reject always results in a rejection, regardless of the input.

Common Interview Questions:

Understanding these static methods can help you answer common interview questions such as:

• How would you handle multiple asynchronous operations in parallel?(Hint: Use Promise.all to wait for all operations to complete or Promise.allSettled if you need results regardless of success or failure.)

• What is the difference between Promise.all and Promise.allSettled?(Hint: Promise.all rejects as soon as one promise fails, while Promise.allSettled waits for all promises to settle, whether fulfilled or rejected.)

• How do you race promises and handle the fastest result?(Hint: Use Promise.race, which resolves or rejects based on the first settled promise, whether fulfilled or rejected.)

• When should you use Promise.any instead of Promise.race?(Hint: Use Promise.any when you only care about the first fulfilled promise and want to ignore rejections, while Promise.race considers both fulfillment and rejection.)

Further References:

Mastering the Promise API and its static methods is crucial for writing efficient asynchronous JavaScript code. Whether handling multiple promises, racing to get the fastest result, or dealing with both successes and failures, these methods offer the flexibility needed for robust application development. Practicing with these methods will prepare you for real-world scenarios and technical interviews alike.

🚀 If you enjoyed this post, why not show your love for coding with Javascript Developer Themed Tees from Usha Creations? Discover the perfect shirt for your next hackathon!

Reply

or to participate.