</>
Skip to content
JavaScript lessons (47/64)

JavaScript — Promises

A promise = a receipt for a future value

Fetching data takes time. Instead of blocking, you get a promise — an IOU:

pending  →  fulfilled (value)   ✓
        →  rejected  (error)    ✗

Creating & consuming

function wait(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

wait(1000).then(() => console.log("one second later"));

The executor runs immediately; resolve(value) fulfills, reject(error) fails:

const coinFlip = new Promise((resolve, reject) => {
    Math.random() < 0.5 ? resolve("heads") : reject(new Error("tails!"));
});

coinFlip
    .then(result => console.log("got:", result))
    .catch(err => console.error("failed:", err.message))
    .finally(() => console.log("flip complete"));
HandlerRuns when
.then(v)fulfilled
.catch(e)rejected
.finally()either way

Chaining — the flat pyramid cure

.then returns a NEW promise, enabling sequences instead of nesting:

getUser(7)
    .then(user => getPosts(user.id))       // return promise → waits
    .then(posts => posts[0])
    .then(post => post.title)
    .then(console.log)
    .catch(handleAnyFailure);              // ONE catch guards the chain

Values flow through: whatever a .then returns becomes the next input.

async/await — promises with better clothes

async function loadTitle() {
    try {
        const user = await getUser(7);      // pause HERE until settled
        const posts = await getPosts(user.id);
        return posts[0].title;
    } catch (e) {
        return "unavailable";
    }
}
loadTitle().then(console.log);

await works only inside async functions; it unwraps promises while keeping try/catch ergonomics. Under the hood it's still promises — same machinery, friendlier syntax. Modern default style.

Parallel vs sequential

// sequential: ~2s total (each waits for the last)
const a = await fetchA();
const b = await fetchB();

// parallel: ~1s total (both in flight together)
const [ra, rb] = await Promise.all([fetchA(), fetchB()]);
HelperBehavior
Promise.allwait all; rejects fast on ANY failure
Promise.allSettledwait all; never rejects; inspect each outcome
Promise.racefirst to settle wins
Promise.anyfirst success
const results = await Promise.allSettled([p1, p2]);
results.filter(r => r.status === "fulfilled").map(r => r.value);

Converting callback APIs

Wrap old-style functions once:

const delay = ms => new Promise(res => setTimeout(res, ms));
await delay(500);

Common mistakes: forgetting await (you hold a promise object, not data); mixing return await confusion in try/catch; creating executor promises when a plain value would do (Promise.resolve(x)).

Mini Practice

  1. Build retryable(delay, fn) that re-runs on rejection up to 3 times
  2. Fetch two URLs in parallel via Promise.all; time both strategies
  3. Convert one .then chain into async/await + try/catch
  4. Use race() for a timeout wrapper around a slow task
  5. allSettled three flaky promises; print per-item outcomes

Next: fetch →

Related Topics

Frequently Asked Questions about Promises

What is Promises in JavaScript?

Promises is a fundamental concept in JavaScript. This lesson explains it step by step with clear examples, making it easy for beginners to understand.

How do I learn Promises?

Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Promises.

Why is Promises important in JavaScript?

Promises is essential for JavaScript development. Understanding this concept will help you write better code and solve real-world problems more effectively.