The Promise API is small but each combinator has a precise rule for when it
fulfills and when it rejects, and choosing the wrong one causes silent data loss
or unhandled rejections. This reference lists every Promise method with its
settlement rule and the equivalent async/await pattern.
Choosing the right combinator
The four static combinators look similar but have distinct failure semantics. Picking the wrong one is one of the most common async bugs in JavaScript:
| Combinator | Fulfills when | Rejects when | Use case |
|---|---|---|---|
Promise.all | All fulfill | First rejects (fast-fail) | Need every result; any failure = abort |
Promise.allSettled | All settle (always) | Never rejects | Partial failure OK; inspect each outcome |
Promise.any | First fulfills | All reject (AggregateError) | First success from redundant sources |
Promise.race | First settles, win or lose | First settles with rejection | Timeout races; first-wins, any outcome |
The key distinction is between any and race: any skips rejections and waits for a fulfillment, while race settles the moment any promise settles — including a rejection.
Instance methods
A Promise is in one of three states: pending, fulfilled, or rejected. Instance methods register callbacks:
then(onFulfilled, onRejected)— transforms the fulfilled value or handles rejection; returns a new promise.catch(onRejected)— shorthand forthen(undefined, onRejected); for error handling in chains.finally(onFinally)— runs on either outcome and passes the original result through unchanged; use for cleanup like hiding a spinner.
Practical patterns
Parallel requests with all-or-nothing failure:
const [user, posts] = await Promise.all([fetchUser(id), fetchPosts(id)]);
Parallel requests tolerating partial failure:
const results = await Promise.allSettled([fetchA(), fetchB(), fetchC()]);
const succeeded = results.filter(r => r.status === "fulfilled").map(r => r.value);
Timeout race:
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error("timed out")), 5000)
);
const result = await Promise.race([fetchData(), timeout]);
Redundant sources, first success wins:
const data = await Promise.any([fetchFromCDN1(), fetchFromCDN2(), fetchFromCDN3()]);
Unhandled rejections
Always attach a .catch() at the end of a chain, or use await inside try/catch. In Node.js an unhandled rejection now crashes the process by default. In browsers it fires the unhandledrejection event and may suppress the error in devtools.
Promise.withResolvers() (ES2024) is the newer alternative to the pattern of capturing resolve and reject from a new Promise(...) constructor when you need to settle the promise from outside its executor.
async/await equivalents
Every promise method has an async/await counterpart. The two styles are interchangeable; async/await compiles to promise chains:
// Promise chain
fetch(url)
.then(r => r.json())
.then(data => process(data))
.catch(err => console.error(err));
// async/await equivalent
async function load() {
try {
const r = await fetch(url);
const data = await r.json();
return process(data);
} catch (err) {
console.error(err);
}
}
await can only be used inside an async function (or at the top level of an ES module). Forgetting that constraint — using await in a regular function — is a syntax error.