Back to Blog Listing

JavaScript Promises Explained from Scratch

Before promises, developers relied on callbacks to handle asynchronous logic. When multiple async tasks depended on each other, this resulted in deeply nested, unmaintainable code known as "Callback Hell" or the "Pyramid of Doom". Promises solve this cleanly.

Constructing a Promise

A promise is created using the new Promise constructor, which takes an executor function with resolve and reject parameters.

const myPromise = new Promise((resolve, reject) => {
  const success = true;
  if (success) {
    resolve("Operation succeeded");
  } else {
    reject("Operation failed");
  }
});

Consuming Promises

Promises are consumed using method handlers:

  • .then(): Runs when the promise resolves. It takes a callback representing the result.
  • .catch(): Runs when the promise rejects. It handles errors.
  • .finally(): Runs regardless of the outcome (resolves or rejects), useful for cleanup tasks like hiding loading spinners.

Promise Combinators

JavaScript provides four utility methods to manage groups of concurrent promises:

  1. Promise.all([p1, p2]): Resolves when all promises resolve. Rejects immediately if any promise rejects.
  2. Promise.allSettled([p1, p2]): Resolves after all promises have either resolved or rejected, providing status logs for each.
  3. Promise.race([p1, p2]): Resolves or rejects as soon as the first promise in the array settles.
  4. Promise.any([p1, p2]): Resolves as soon as any promise resolves. Rejects only if all promises reject.
Promise.allSettled([
  Promise.resolve(100),
  Promise.reject('error')
]).then(results => console.log(results));
// [{status: 'fulfilled', value: 100}, {status: 'rejected', reason: 'error'}]
💻

Try this code in our online compiler!

Don't just read about it. Write, run, and experiment with these JavaScript concepts instantly on our online workspace with autocomplete suggestions.

Share this tutorial:

CodeCompile