JavaScript Promises

A Promise is an object that represents the eventual result of an asynchronous operation. Instead of receiving a result immediately, a promise says: "I will give the result later — either successfully or with an error."

Real-life analogy: When ordering food at a restaurant, a receipt is given — a promise that food will arrive. It may succeed (food delivered) or fail (item unavailable). While waiting, other activities can continue.

Why Promises?

Before promises, asynchronous operations relied on callbacks — functions passed into other functions to run after completion. Deeply nested callbacks created what is called "callback hell," making code difficult to read and maintain.

// Callback hell — hard to read and manage
getUser(id, function(user) {
  getOrders(user.id, function(orders) {
    getOrderDetails(orders[0], function(details) {
      getInvoice(details, function(invoice) {
        console.log(invoice);  // Deeply nested!
      });
    });
  });
});

Promises solve this with a clean chain-based syntax.

Promise States

A promise can be in one of three states:

StateMeaning
PendingInitial state — operation not yet complete
FulfilledOperation completed successfully
RejectedOperation failed with an error

Once fulfilled or rejected, a promise is settled and its state cannot change.

Creating a Promise

let myPromise = new Promise(function(resolve, reject) {
  // Simulate an async operation
  let success = true;

  if (success) {
    resolve("Operation completed!");  // Fulfill the promise
  } else {
    reject("Something went wrong.");  // Reject the promise
  }
});

Consuming a Promise — .then(), .catch(), .finally()

myPromise
  .then(function(result) {
    console.log("Success:", result);
  })
  .catch(function(error) {
    console.log("Error:", error);
  })
  .finally(function() {
    console.log("Promise settled.");
  });

With Arrow Functions (Modern Style)

myPromise
  .then(result => console.log("Success:", result))
  .catch(error => console.log("Error:", error))
  .finally(() => console.log("Done."));

Promise with a Delay — Simulating Async Operations

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      let data = { user: "Neha", score: 92 };
      resolve(data);
    }, 2000);  // Simulates a 2-second API call
  });
}

fetchData()
  .then(data => {
    console.log("Data received:", data.user, data.score);
  })
  .catch(err => {
    console.log("Failed:", err);
  });

console.log("Waiting for data...");  // Runs first while promise is pending

Promise Chaining

Multiple asynchronous operations can be chained using .then(). Each .then() receives the result of the previous one and returns a new promise.

function step1() {
  return new Promise(resolve => setTimeout(() => resolve("Step 1 done"), 1000));
}

function step2(prev) {
  return new Promise(resolve => setTimeout(() => resolve(prev + " → Step 2 done"), 1000));
}

function step3(prev) {
  return new Promise(resolve => setTimeout(() => resolve(prev + " → Step 3 done"), 1000));
}

step1()
  .then(result => step2(result))
  .then(result => step3(result))
  .then(finalResult => console.log(finalResult))
  .catch(err => console.log("Error:", err));

// After 3 seconds:
// Step 1 done → Step 2 done → Step 3 done

Rejecting and Catching Errors in Chains

function validateAge(age) {
  return new Promise((resolve, reject) => {
    if (age >= 18) {
      resolve("Access granted!");
    } else {
      reject("You must be 18 or older.");
    }
  });
}

validateAge(15)
  .then(msg => console.log(msg))
  .catch(err => console.log("Rejected:", err));
// Rejected: You must be 18 or older.

Promise.all() — Run Multiple Promises Simultaneously

Promise.all() takes an array of promises and waits for all of them to resolve. If any one fails, the entire call rejects.

let p1 = new Promise(resolve => setTimeout(() => resolve("Data A"), 1000));
let p2 = new Promise(resolve => setTimeout(() => resolve("Data B"), 500));
let p3 = new Promise(resolve => setTimeout(() => resolve("Data C"), 800));

Promise.all([p1, p2, p3])
  .then(results => {
    console.log(results);  // ["Data A", "Data B", "Data C"]
  })
  .catch(err => console.log("One failed:", err));

Promise.allSettled() — Wait for All, Regardless of Outcome

Promise.allSettled() waits for all promises to finish and returns all outcomes, both fulfilled and rejected.

let p1 = Promise.resolve("Success!");
let p2 = Promise.reject("Failed!");
let p3 = Promise.resolve("Also success!");

Promise.allSettled([p1, p2, p3]).then(results => {
  results.forEach(result => {
    if (result.status === "fulfilled") {
      console.log("Fulfilled:", result.value);
    } else {
      console.log("Rejected:", result.reason);
    }
  });
});
// Fulfilled: Success!
// Rejected: Failed!
// Fulfilled: Also success!

Promise.race() — First One Wins

Promise.race() resolves or rejects as soon as the first promise settles.

let fast = new Promise(resolve => setTimeout(() => resolve("Fast!"), 300));
let slow = new Promise(resolve => setTimeout(() => resolve("Slow!"), 1000));

Promise.race([fast, slow])
  .then(winner => console.log("Winner:", winner));
// Winner: Fast!

Promise.any() — First Successful One

Promise.any() resolves with the first fulfilled promise. It only rejects if all promises fail.

let p1 = Promise.reject("Failed 1");
let p2 = Promise.resolve("Success!");
let p3 = Promise.reject("Failed 3");

Promise.any([p1, p2, p3])
  .then(result => console.log("First success:", result));
// First success: Success!

Promise Methods Comparison

MethodResolves WhenRejects When
Promise.all()All promises fulfillAny one rejects
Promise.allSettled()All promises settle (always)Never rejects
Promise.race()First promise settlesFirst promise rejects
Promise.any()First promise fulfillsAll promises reject

Practical Example — Simulated User Login

function checkCredentials(username, password) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (username === "admin" && password === "1234") {
        resolve({ userId: 101, name: "Admin User" });
      } else {
        reject("Invalid username or password.");
      }
    }, 1500);
  });
}

checkCredentials("admin", "1234")
  .then(user => {
    console.log(`Welcome, ${user.name}! (ID: ${user.userId})`);
  })
  .catch(err => {
    console.log("Login failed:", err);
  })
  .finally(() => {
    console.log("Login attempt complete.");
  });

// Welcome, Admin User! (ID: 101)
// Login attempt complete.

Key Points to Remember

  • A Promise represents a future value — either fulfilled (success) or rejected (failure)
  • Use .then() to handle success, .catch() for errors, and .finally() for cleanup
  • Promises can be chained to handle sequential async operations cleanly
  • Promise.all() waits for all to succeed; fails if any one fails
  • Promise.allSettled() waits for all regardless of outcome
  • Promise.race() resolves with the first settled promise
  • Promise.any() resolves with the first fulfilled promise
  • Always handle errors with .catch() to prevent unhandled rejection warnings

Leave a Comment

Your email address will not be published. Required fields are marked *