CodeOath
← All posts
JavaScript75 min total · 15 parts

JavaScript Core Concepts: Scope, Closures, `this`, and the Event Loop

Contents — Part 10 of 15: Promises: Representing a Future Value
Part 10 of 15 · ~2 min

Promises: Representing a Future Value

A Promise represents a value that may not be available yet, in one of three states: pending, fulfilled, or rejected — and once settled (fulfilled or rejected), it never changes state again.

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const success = true;
    if (success) resolve("done!");
    else reject(new Error("failed"));
  }, 1000);
});

promise
  .then((value) => console.log(value))   // runs only on fulfillment
  .catch((error) => console.error(error)) // runs only on rejection
  .finally(() => console.log("always runs, regardless of outcome"));

Chaining and error propagation

Each .then() returns a new Promise, which is what makes chaining work — and a thrown error or rejection skips forward past any .then()s to the next .catch():

fetchUser(id)
  .then((user) => fetchPosts(user.id))   // returns a new Promise, chained onto
  .then((posts) => posts[0])
  .catch((err) => console.error("failed at some step:", err)); // catches a rejection from ANY step above

Combining multiple Promises

MethodResolves whenRejects when
Promise.all([...])Every Promise fulfills — result is an array of values, in orderAny single Promise rejects — immediately, discarding the others' results
Promise.allSettled([...])Every Promise settles, fulfilled or rejected — never itself rejectsNever — each result reports its own status
Promise.race([...])The first Promise to settle, fulfilled or rejectedSame — whichever settles first, win or lose
Promise.any([...])The first Promise to fulfillOnly if all of them reject
const [user, posts] = await Promise.all([fetchUser(id), fetchPosts(id)]);
// runs both requests concurrently rather than one after another — much faster than two sequential awaits

Promise.all failing fast (on the very first rejection) is exactly why Promise.allSettled exists — for cases like "send five independent notifications, and report which ones failed" where one failure shouldn't discard the results of the four that succeeded.