0
0
Node.jsframework~15 mins

Promise.race and Promise.allSettled in Node.js - Deep Dive

Choose your learning style9 modes available
Overview - Promise.race and Promise.allSettled
What is it?
Promise.race and Promise.allSettled are two ways to handle multiple promises in JavaScript. Promise.race returns the result of the first promise that settles, whether it resolves or rejects. Promise.allSettled waits for all promises to settle and gives you their results, regardless of success or failure. These methods help manage multiple asynchronous tasks efficiently.
Why it matters
Without these methods, handling multiple asynchronous operations would be complicated and error-prone. Promise.race lets you react quickly to the fastest result, useful for timeouts or first response wins. Promise.allSettled ensures you know the outcome of every task, even if some fail, which is important for robust applications. Without them, developers would write more complex and fragile code.
Where it fits
Before learning these, you should understand basic promises and async/await in JavaScript. After mastering these, you can explore advanced concurrency patterns, error handling strategies, and libraries that build on promises like RxJS or async.js.
Mental Model
Core Idea
Promise.race returns the first settled promise's result, while Promise.allSettled waits for all promises to finish and reports each outcome.
Think of it like...
Imagine a race where the winner is the first to cross the finish line (Promise.race), versus a group project where you wait for every member to finish their part and then review everyone's work (Promise.allSettled).
┌───────────────┐       ┌───────────────┐
│ Promise 1     │       │ Promise 1     │
│ (resolves)   │       │ (resolves)   │
└──────┬────────┘       └──────┬────────┘
       │                       │
┌──────▼────────┐       ┌──────▼────────┐
│ Promise 2     │       │ Promise 2     │
│ (rejects)    │       │ (rejects)    │
└──────┬────────┘       └──────┬────────┘
       │                       │
┌──────▼────────┐       ┌──────▼────────┐
│ Promise 3     │       │ Promise 3     │
│ (resolves)   │       │ (resolves)   │
└──────────────┘       └──────────────┘

Promise.race: Result from first settled promise (left side)
Promise.allSettled: Results from all promises after all settle (right side)
Build-Up - 7 Steps
1
FoundationUnderstanding Basic Promises
🤔
Concept: Learn what promises are and how they represent future values in JavaScript.
A promise is like a placeholder for a value that will be available later. It can be pending, fulfilled (resolved), or rejected. You use .then() to handle success and .catch() for errors. For example: const p = new Promise((resolve) => setTimeout(() => resolve('Done'), 1000)); p.then(result => console.log(result));
Result
After 1 second, 'Done' is printed to the console.
Understanding promises is essential because Promise.race and Promise.allSettled work by managing multiple promises together.
2
FoundationHandling Multiple Promises Basics
🤔
Concept: Learn how to run multiple promises and wait for all to finish using Promise.all.
Promise.all takes an array of promises and returns a new promise that resolves when all input promises resolve, or rejects if any reject. Example: const p1 = Promise.resolve(1); const p2 = Promise.resolve(2); Promise.all([p1, p2]).then(results => console.log(results));
Result
[1, 2] is printed after both promises resolve.
Knowing Promise.all sets the stage to understand why Promise.race and Promise.allSettled offer different behaviors for multiple promises.
3
IntermediateUsing Promise.race for Fastest Result
🤔Before reading on: do you think Promise.race waits for all promises or just the first one to settle? Commit to your answer.
Concept: Promise.race returns a promise that settles as soon as any input promise settles, with that promise's value or reason.
Example: const p1 = new Promise(resolve => setTimeout(() => resolve('First'), 500)); const p2 = new Promise(resolve => setTimeout(() => resolve('Second'), 1000)); Promise.race([p1, p2]).then(result => console.log(result)); This prints 'First' after 500ms because p1 settles first.
Result
'First' is printed quickly, ignoring the slower promise.
Understanding Promise.race helps you react to the fastest outcome, useful for timeouts or competing tasks.
4
IntermediateUsing Promise.allSettled for Complete Outcomes
🤔Before reading on: do you think Promise.allSettled rejects if one promise rejects, or does it always resolve? Commit to your answer.
Concept: Promise.allSettled waits for all promises to settle and returns an array describing each promise's outcome, never rejecting itself.
Example: const p1 = Promise.resolve('Success'); const p2 = Promise.reject('Error'); Promise.allSettled([p1, p2]).then(results => console.log(results)); Output: [ { status: 'fulfilled', value: 'Success' }, { status: 'rejected', reason: 'Error' } ]
Result
An array with each promise's status and value or reason is printed.
Promise.allSettled lets you handle all results safely, even if some promises fail.
5
IntermediateComparing Promise.race and Promise.allSettled
🤔Before reading on: which method would you use to get the first result quickly, and which to get all results regardless of success? Commit to your answer.
Concept: Promise.race returns the first settled promise's result; Promise.allSettled waits for all promises and reports all results.
Use Promise.race when you want the fastest response, like fetching from multiple servers and using the quickest. Use Promise.allSettled when you want to know the outcome of every task, like processing multiple uploads and reporting success or failure for each.
Result
You understand when to choose each method based on your needs.
Knowing the difference prevents bugs where you either wait too long or miss errors.
6
AdvancedHandling Errors with Promise.race
🤔Before reading on: do you think Promise.race ignores rejected promises if another promise resolves first? Commit to your answer.
Concept: Promise.race settles as soon as any promise settles, whether resolved or rejected, so errors can cause immediate rejection.
Example: const p1 = new Promise((_, reject) => setTimeout(() => reject('Fail'), 300)); const p2 = new Promise(resolve => setTimeout(() => resolve('Win'), 500)); Promise.race([p1, p2]) .then(result => console.log('Resolved:', result)) .catch(error => console.log('Rejected:', error)); Output: 'Rejected: Fail' after 300ms because p1 rejects first.
Result
Promise.race rejects immediately if the first settled promise rejects.
Understanding this prevents unexpected crashes when using Promise.race with promises that might reject.
7
ExpertOptimizing with Promise.allSettled in Production
🤔Before reading on: do you think Promise.allSettled can be used to implement retry logic for failed promises? Commit to your answer.
Concept: Promise.allSettled can be combined with logic to retry failed promises or handle partial failures gracefully in real-world apps.
In production, you might run multiple API calls and want to retry only the failed ones. Using Promise.allSettled, you get the status of each call, then selectively retry failures without restarting successful ones. This improves efficiency and user experience. Example pattern: const results = await Promise.allSettled(tasks); const failed = results.filter(r => r.status === 'rejected'); // Retry failed promises here
Result
You can build robust systems that handle partial failures without losing progress.
Knowing how to leverage Promise.allSettled for retries and partial success handling is a key expert skill.
Under the Hood
Promises in JavaScript are objects representing future completion or failure of asynchronous operations. Promise.race creates a new promise that listens to all input promises and settles as soon as the first input settles, forwarding that result or error. Promise.allSettled creates a new promise that waits for all input promises to settle, collecting their results or errors into an array. Internally, both use microtasks to schedule callbacks after promise state changes.
Why designed this way?
These methods were designed to simplify common asynchronous patterns. Promise.race addresses the need to react quickly to the first available result, useful in time-sensitive scenarios. Promise.allSettled was introduced to handle multiple promises without failing fast, allowing developers to see all outcomes. Alternatives like Promise.all reject immediately on any failure, which is not always desirable.
┌─────────────────────────────┐
│ Input Promises Array         │
│ ┌───────┐ ┌───────┐ ┌───────┐ │
│ │ P1    │ │ P2    │ │ P3    │ │
│ └───┬───┘ └───┬───┘ └───┬───┘ │
└──────┼──────────┼────────┼────┘
       │          │        │
       ▼          ▼        ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ Settled P1│ │ Settled P2│ │ Settled P3│
└────┬──────┘ └────┬──────┘ └────┬──────┘
     │             │             │
     ├─────────────┼─────────────┤
     ▼             ▼             ▼
┌─────────────────────────────────────┐
│ Promise.race settles on first settled │
│ Promise.allSettled waits for all     │
│ and collects all results             │
└─────────────────────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does Promise.race wait for all promises to finish before settling? Commit to yes or no.
Common Belief:Promise.race waits for all promises to finish and then returns the fastest result.
Tap to reveal reality
Reality:Promise.race settles as soon as the first promise settles, ignoring the rest.
Why it matters:Believing this causes developers to expect all promises to complete, leading to bugs when some promises are still running or ignored.
Quick: Does Promise.allSettled reject if any promise rejects? Commit to yes or no.
Common Belief:Promise.allSettled rejects if any input promise rejects, like Promise.all.
Tap to reveal reality
Reality:Promise.allSettled always resolves with an array of all results, regardless of individual rejections.
Why it matters:Misunderstanding this leads to unnecessary try-catch blocks or missed error handling opportunities.
Quick: Can Promise.race be used safely without handling rejections? Commit to yes or no.
Common Belief:Promise.race only resolves and never rejects if one promise resolves first.
Tap to reveal reality
Reality:Promise.race can reject immediately if the first settled promise rejects.
Why it matters:Ignoring this causes unhandled promise rejections and crashes in applications.
Quick: Does Promise.allSettled provide the resolved values directly like Promise.all? Commit to yes or no.
Common Belief:Promise.allSettled returns an array of resolved values, ignoring rejected ones.
Tap to reveal reality
Reality:Promise.allSettled returns an array of objects describing each promise's status and value or reason.
Why it matters:Assuming direct values causes errors when accessing results, leading to bugs in result processing.
Expert Zone
1
Promise.race does not cancel other promises; they continue running in the background, which can cause side effects or resource usage.
2
Promise.allSettled's result objects include 'status' fields that allow fine-grained handling of each promise's outcome without exceptions.
3
Using Promise.allSettled with large numbers of promises can impact performance and memory, so batching or throttling is often necessary.
When NOT to use
Avoid Promise.race when you need all results or must handle every error explicitly; use Promise.all or Promise.allSettled instead. Avoid Promise.allSettled when you want to fail fast on errors; use Promise.all for that. For cancelable operations, consider AbortController or libraries supporting cancellation.
Production Patterns
In production, Promise.race is used for implementing timeouts by racing a task against a timeout promise. Promise.allSettled is used in batch processing where partial failures are expected and must be reported, such as uploading multiple files or querying multiple APIs. Combining Promise.allSettled with retry logic for failed promises is a common robust pattern.
Connections
Event Loop
Promise resolution and callbacks rely on the event loop to schedule microtasks.
Understanding the event loop helps explain why promise callbacks run asynchronously after the current code finishes.
Timeouts and Cancellation
Promise.race is often combined with timeout promises to implement cancellation-like behavior.
Knowing how to race a task against a timeout promise enables building responsive and resilient asynchronous code.
Project Management
Promise.allSettled resembles tracking all team members' task completion status regardless of success or failure.
This connection helps appreciate the value of comprehensive status reporting in both software and real-world projects.
Common Pitfalls
#1Expecting Promise.race to wait for all promises to finish.
Wrong approach:Promise.race([promise1, promise2]).then(result => console.log('All done:', result));
Correct approach:Promise.all([promise1, promise2]).then(results => console.log('All done:', results));
Root cause:Misunderstanding that Promise.race settles on the first promise, not all.
#2Assuming Promise.allSettled rejects if any promise rejects.
Wrong approach:try { await Promise.allSettled([p1, p2]); } catch (e) { console.log('Error caught'); }
Correct approach:const results = await Promise.allSettled([p1, p2]); // Handle results individually without try-catch
Root cause:Confusing Promise.allSettled behavior with Promise.all.
#3Not handling rejection in Promise.race leading to unhandled errors.
Wrong approach:Promise.race([p1, p2]).then(result => console.log(result)); // no catch
Correct approach:Promise.race([p1, p2]).then(result => console.log(result)).catch(error => console.error(error));
Root cause:Ignoring that Promise.race can reject if the first settled promise rejects.
Key Takeaways
Promise.race returns the first promise that settles, whether it resolves or rejects, allowing fast reactions to the earliest result.
Promise.allSettled waits for all promises to settle and returns detailed results for each, enabling comprehensive outcome handling.
Promise.race does not cancel other promises; they continue running even after the race settles.
Promise.allSettled never rejects, so it is ideal for scenarios where you want to know every promise's outcome without failing fast.
Choosing between Promise.race, Promise.all, and Promise.allSettled depends on whether you want the fastest result, all successful results, or all results regardless of success.