Skip to main content
โณintermediate

Promises

Promises represent a value that will be available in the future. They fix callback hell with chainable .then() and centralized .catch() error handling.

What is a Promise?

A Promise is an object representing the eventual completion or failure of an asynchronous operation. It's a placeholder for a future value.

A Promise is in one of three states:

  • Pending โ€” initial state, operation not complete
  • Fulfilled โ€” operation completed successfully (has a value)
  • Rejected โ€” operation failed (has a reason/error)
hljs javascript
const promise = new Promise((resolve, reject) => {
  const success = true;

  if (success) {
    resolve("Operation succeeded!");  // fulfill with a value
  } else {
    reject(new Error("Something went wrong")); // reject with an error
  }
});

promise
  .then(value => console.log(value))   // "Operation succeeded!"
  .catch(err => console.error(err));

Creating Promises

hljs javascript
// Wrap a callback-based function in a Promise
function delay(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

function fetchData(url) {
  return new Promise((resolve, reject) => {
    // Simulate network request
    setTimeout(() => {
      if (url.includes("valid")) {
        resolve({ data: "some data" });
      } else {
        reject(new Error("Invalid URL"));
      }
    }, 500);
  });
}

Chaining .then()

The key feature: each .then() returns a new Promise, enabling chaining:

hljs javascript
function getUser(id) {
  return Promise.resolve({ id, name: "Alice", teamId: 5 });
}

function getTeam(teamId) {
  return Promise.resolve({ id: teamId, name: "Engineering" });
}

function getTeamMembers(teamId) {
  return Promise.resolve(["Alice", "Bob", "Charlie"]);
}

// Clean chain โ€” no nesting!
getUser(1)
  .then(user => {
    console.log("User:", user.name);
    return getTeam(user.teamId); // return a promise to chain
  })
  .then(team => {
    console.log("Team:", team.name);
    return getTeamMembers(team.id);
  })
  .then(members => {
    console.log("Members:", members);
  })
  .catch(err => {
    console.error("Something failed:", err.message);
  });

๐Ÿ’กInfo

Whatever you return from a .then() callback becomes the resolved value for the next .then(). If you return a Promise, the chain waits for it to resolve.

Error Handling with .catch()

.catch() handles any rejection in the chain above it:

hljs javascript
Promise.resolve("start")
  .then(val => {
    console.log(val);        // "start"
    throw new Error("Oops"); // throws an error
  })
  .then(val => {
    console.log("Never runs");
  })
  .catch(err => {
    console.error("Caught:", err.message); // "Caught: Oops"
    return "recovered";                    // can return to continue chain
  })
  .then(val => {
    console.log("After recovery:", val);   // "After recovery: recovered"
  });

.finally() โ€” Cleanup

Runs after the Promise settles (fulfilled or rejected), great for cleanup:

hljs javascript
let isLoading = true;

fetchData("valid-url")
  .then(data => {
    console.log("Got data:", data);
  })
  .catch(err => {
    console.error("Error:", err.message);
  })
  .finally(() => {
    isLoading = false; // always runs
    console.log("Loading done. isLoading:", isLoading);
  });

Static Promise Methods

Promise.resolve / Promise.reject

hljs javascript
// Already-resolved/rejected promises
Promise.resolve(42).then(v => console.log(v)); // 42
Promise.reject(new Error("fail")).catch(e => console.error(e.message)); // "fail"

Promise.all โ€” All must succeed

hljs javascript
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);

Promise.all([p1, p2, p3])
  .then(values => console.log(values)) // [1, 2, 3]
  .catch(err => console.error("One failed:", err));
// If ANY promise rejects, the whole thing rejects

Practical use โ€” parallel API calls:

hljs javascript
async function loadDashboard(userId) {
  const [user, posts, followers] = await Promise.all([
    fetchUser(userId),
    fetchPosts(userId),
    fetchFollowers(userId),
  ]);
  return { user, posts, followers };
}
// All 3 requests run in parallel โ€” much faster than sequential!

Promise.allSettled โ€” All complete regardless

hljs javascript
const promises = [
  Promise.resolve("success"),
  Promise.reject(new Error("fail")),
  Promise.resolve("another success"),
];

Promise.allSettled(promises).then(results => {
  results.forEach(result => {
    if (result.status === "fulfilled") {
      console.log("โœ“", result.value);
    } else {
      console.log("โœ—", result.reason.message);
    }
  });
});
// โœ“ success
// โœ— fail
// โœ“ another success

Promise.race โ€” First to settle wins

hljs javascript
const fast = new Promise(resolve => setTimeout(() => resolve("fast"), 100));
const slow = new Promise(resolve => setTimeout(() => resolve("slow"), 500));

Promise.race([fast, slow]).then(result => {
  console.log(result); // "fast"
});

// Timeout pattern
function withTimeout(promise, ms) {
  const timeout = new Promise((_, reject) =>
    setTimeout(() => reject(new Error("Timed out")), ms)
  );
  return Promise.race([promise, timeout]);
}

Promise.any โ€” First to succeed

hljs javascript
Promise.any([
  Promise.reject("fail 1"),
  Promise.resolve("success"),
  Promise.reject("fail 2"),
]).then(result => console.log(result)); // "success"
// Only rejects if ALL promises reject (AggregateError)

Converting Callbacks to Promises

hljs javascript
// Manual wrapping
function readFilePromise(path) {
  return new Promise((resolve, reject) => {
    fs.readFile(path, "utf8", (err, data) => {
      if (err) reject(err);
      else resolve(data);
    });
  });
}

// Node's built-in promisify
const { promisify } = require("util");
const readFile = promisify(fs.readFile);
readFile("data.txt", "utf8").then(data => console.log(data));
โ–ถTry it yourself

Key Takeaways

  • A Promise is in one of 3 states: pending, fulfilled, or rejected
  • .then() chains handle success; .catch() handles errors; .finally() always runs
  • Return a Promise from .then() to chain asynchronous operations
  • Promise.all() โ€” all succeed or fail together; great for parallel requests
  • Promise.allSettled() โ€” waits for all, regardless of success/failure
  • Promise.race() โ€” first to settle wins (useful for timeouts)

Ready to test your knowledge?

Take a quiz on what you just learned.

Take the Quiz โ†’