← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Promise.allSettled / Promise.any / Promise.race

JavaScript ES2020 Intermediate
debt(d7/e5/b3/t8)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). No detection_hints.tools specified; default JavaScript linters (ESLint) don't flag Promise combinator misuse by default. The wrong combinator is syntactically valid and only fails at runtime under specific conditions (e.g., when a promise rejects in Promise.all() or when all promises reject in Promise.any()). Runtime testing or code review is needed to catch these mistakes.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix suggests replacing the combinator (allSettled vs all vs any vs race), but this often requires changes to how results are handled: Promise.all() → allSettled() means refactoring the catch block and result inspection logic. Adding AbortController for proper race() cancellation spans initialization, cleanup, and error handling. Not a one-line swap; typically requires updates to result processing across several lines or methods.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The choice of Promise combinator is typically isolated within individual async functions or utility helpers. It doesn't impose a system-wide tax unless the same anti-pattern is repeated across many components. Once chosen, it affects only that specific operation's error handling and result processing, not the broader architecture or all future maintainers uniformly.

t8 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The canonical misconception is that Promise.race() cancels losing promises — it does not. This contradicts intuition from similar concepts (e.g., goroutine cancellation patterns, some async libraries). Additionally, Promise.allSettled() never rejects, which contradicts the behavior of Promise.all(). The difference between any() and race() is also a behavioral trap: which combinator to use for timeouts vs. first-success. Competent developers unfamiliar with Promise semantics will guess wrong about cancellation and rejection behavior.

About DEBT scoring →

Also Known As

Promise.allSettled Promise.any Promise.race Promise combinators

TL;DR

Three Promise combinators for handling multiple async operations — allSettled() waits for all to complete regardless of failure, any() resolves with the first success, race() resolves or rejects with the first to settle.

Explanation

Promise.all() is the most known combinator — it resolves when all promises resolve and rejects immediately on the first rejection (fail-fast). Three others cover different patterns: Promise.allSettled() (ES2020) waits for all promises to settle and returns an array of {status, value/reason} objects — none are skipped on failure. Promise.any() (ES2021) resolves with the first successful promise, only rejecting if all promises reject (with an AggregateError). Promise.race() resolves or rejects with whichever promise settles first — useful for timeouts. Combining these correctly depends entirely on whether you want fail-fast, fail-never, or first-success semantics.

Common Misconception

Promise.race() cancels the slower promises when one wins. It does not — all promises continue running; race() just ignores the results of non-winners. The underlying work (API calls, timers) is not cancelled.

Why It Matters

Choosing the wrong Promise combinator causes subtle bugs: using Promise.all() when you want allSettled() means one failed API call silently aborts all the others. Using race() for a timeout without cancellation causes the losing promise to continue running in the background. Knowing which combinator fits which use case prevents these issues.

Common Mistakes

  • Using Promise.all() for independent operations where partial success is acceptable — one failure kills everything unnecessarily.
  • Not handling AggregateError from Promise.any() — when all promises reject, any() throws AggregateError containing all rejection reasons; catch and handle it.
  • Race condition with Promise.race() and side effects — the losing promises continue running and may modify shared state after the winner has already returned.
  • Forgetting that allSettled() never rejects — you must inspect each result's status field; the outer await will always succeed.

Code Examples

✗ Vulnerable
// ❌ Promise.all() fails-fast — one error aborts everything
const [user, orders, recommendations] = await Promise.all([
    fetchUser(id),          // If this fails...
    fetchOrders(id),        // ...these are abandoned
    fetchRecommendations(id), // ...and this too
]);
// User sees blank page instead of partial content

// ❌ Race timeout without cancellation — fetch continues in background
const result = await Promise.race([
    fetch('/api/data'),
    new Promise((_, reject) => setTimeout(() => reject('Timeout'), 3000)),
]);
✓ Fixed
// ✅ allSettled — partial failures show graceful degradation
const results = await Promise.allSettled([
    fetchUser(id),
    fetchOrders(id),
    fetchRecommendations(id),
]);

const [user, orders, recs] = results.map(r =>
    r.status === 'fulfilled' ? r.value : null
);
// Page renders with whatever data loaded successfully

// ✅ Race timeout with AbortController — actually cancels the request
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 3000);

try {
    const result = await fetch('/api/data', { signal: controller.signal });
    clearTimeout(timeout);
    return await result.json();
} catch (e) {
    if (e.name === 'AbortError') throw new Error('Request timed out');
    throw e;
}

// ✅ any() — first working CDN wins
const image = await Promise.any([
    fetch('https://cdn1.example.com/img.jpg'),
    fetch('https://cdn2.example.com/img.jpg'),
]);

Added 23 Mar 2026
Edited 5 Apr 2026
Views 72
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 2 pings F 0 pings S 1 ping S 1 ping M 0 pings T 0 pings W 0 pings T 2 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 0 pings F 2 pings S 1 ping S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 2 pings S 0 pings S 1 ping M
SEMrush 1
No pings yesterday
Amazonbot 10 ChatGPT 6 Google 6 SEMrush 5 Ahrefs 4 Perplexity 3 Brave Search 3 Meta AI 2 Scrapy 2 PetalBot 2 Majestic 1 Claude 1 Bing 1 Twitter/X 1 Applebot 1
crawler 44 crawler_json 4
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
JavaScript javascript The programming language of the browser — it reads and modifies the page (the DOM), reacts to user events, and fetches data without reloading.

JavaScript is the only language browsers execute, so every interactive behaviour on the web goes through it. Its two defining traits — single-threaded event loop and loose typing (== coercion) — explain the majority of both its bugs and its design patterns.

💡 Default to const, use === always, and reach for let only when a value genuinely reassigns.

Ask Codex about JavaScript →
DEV INTEL Tools & Severity
⚙ Fix effort: Low
⚡ Quick Fix
For operations where partial failure is acceptable (loading multiple independent widgets), use allSettled(). For the first available data source, use any(). For timeouts, use race() with AbortController to actually cancel the request.
📦 Applies To
javascript ES2020 web cli


✓ schema.org compliant