← Back to JavaScript Course | Chapter 4: Modern JS, Async & DOM | Lesson 16 of 26

JS Promises

Think of ordering food at a restaurant, you don't get your meal instantly, the server gives you a receipt as a promise that food is coming, and eventually that promise resolves into either your meal arriving or the kitchen telling you they're out of an ingredient. A JavaScript Promise works the same way, it represents a value that isn't available yet but will be at some point, either successfully (fulfilled) or unsuccessfully (rejected), and lets your code react once that outcome is known. Promises are essential for handling anything that takes time, like fetching tutorial data from a server behind the scenes on cookiescursor.com, without freezing the rest of the page while waiting.

What Is a Promise

A Promise is an object representing the eventual result of an operation that hasn't finished yet, starting in a pending state, and eventually settling into either fulfilled, meaning it succeeded, or rejected, meaning it failed.

Note: Think of a promise's three states as a package's shipping status, pending means still in transit, fulfilled means delivered, rejected means lost.

Warning: A promise can only settle once, either fulfilled or rejected, never both, and its state can never change again after settling.

Example: What Is a Promise

javascript
const promise = new Promise((resolve, reject) => {
  resolve("Success!");
});
console.log(promise); // Promise {<fulfilled>: 'Success!'}

then, catch, and finally

.then() runs a function when a promise successfully fulfills, .catch() runs a function when a promise rejects, and .finally() runs a function regardless of whether the promise succeeded or failed.

Note: .finally() is a great place for cleanup logic, like hiding a loading spinner, since it runs no matter how the promise settles.

Warning: Skipping .catch() entirely means errors go unhandled, which can produce confusing, silent failures in your application.

Example: then, catch, and finally

javascript
const promise = new Promise((resolve) => resolve("Done"));
promise
  .then(result => console.log(result))
  .catch(err => console.log(err))
  .finally(() => console.log("Finished"));

Chaining Promises

Multiple .then() calls can be chained together, with each one receiving the value returned by the previous one, letting you express a sequence of asynchronous steps in a clean, readable, top-to-bottom order.

Note: Returning a value from inside a .then() automatically passes that value along to the next .then() in the chain.

Warning: Forgetting to return a value from inside a .then() callback causes the next step in the chain to receive undefined instead of the expected data.

Example: Chaining Promises

javascript
Promise.resolve(1)
  .then(n => n + 1)
  .then(n => n * 2)
  .then(result => console.log(result)); // 4

Promise.all

Promise.all() takes an array of promises and returns a single new promise that fulfills once every one of them has fulfilled, with an array of all their results, or rejects immediately if any single one rejects.

Note: Promise.all() is ideal when you need several independent operations to all finish before continuing, like loading multiple resources together.

Warning: If even one promise passed to Promise.all() rejects, the entire combined promise rejects immediately, even if the others would have succeeded.

Example: Promise.all

javascript
Promise.all([
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.resolve(3),
]).then(results => console.log(results)); // [1, 2, 3]

Promise.race

Promise.race() takes an array of promises and settles as soon as the very first one settles, whether it fulfills or rejects, effectively racing them against each other and returning the fastest outcome.

Note: Promise.race() is a common technique for implementing a timeout, racing a real operation against a promise that rejects after a set delay.

Warning: Promise.race() settles based on speed alone, it doesn't wait to confirm whether a faster rejection was actually less important than a slower success.

Example: Promise.race

javascript
Promise.race([
  new Promise(resolve => setTimeout(() => resolve("slow"), 100)),
  new Promise(resolve => setTimeout(() => resolve("fast"), 10)),
]).then(result => console.log(result)); // "fast"
Common Mistakes
  1. Forgetting to add a .catch() to handle errors, an unhandled promise rejection can silently fail or clutter the console with warnings.
  2. Nesting .then() calls deeply instead of chaining them, which quickly becomes hard to read compared to a flat chain.
  3. Assuming a promise resolves immediately, code after creating a promise runs before its result is ready, that's the entire point of using one.
Chapter Summary
  • A promise represents a value that will be available later, existing in one of three states: pending, fulfilled, or rejected.
  • .then() handles a successful result, .catch() handles an error, and .finally() runs regardless of the outcome.
  • Promise.all() waits for multiple promises to finish together, and Promise.race() resolves as soon as the first one finishes.
Browser Support

Promises have been supported in all major browsers since 2015 and are a completely standard part of modern JavaScript.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.