If you’ve worked with JavaScript promises, you might have found yourself asking the question: does Promise race cancel promise? This seemingly simple question has confused developers for years, especially when working with concurrent asynchronous operations.
In this article, we’ll break down how Promise.race()
works, whether it cancels unresolved promises, and what implications it has for your code. We’ll also look at 7 important facts that will help you write better asynchronous code and avoid subtle bugs.
Let’s dive in!
Read also: HTML Meta Tag Redirect: 7 Powerful Ways for Seamless Redirection
What Is Promise.race()
?
JavaScript’s Promise.race()
method takes an iterable of promises and returns a new promise that settles as soon as one of the promises settles (either fulfilled or rejected). The first one to do so “wins the race.”
Promise.race([
fetch('/api/data'),
new Promise((_, reject) => setTimeout(() => reject('Timeout'), 3000))
]);
In the above example, if the fetch takes more than 3 seconds, the race is lost, and the timeout error is triggered instead.
But does Promise race cancel promise that didn’t win? Let’s examine.
Does Promise Race Cancel Promise? The Short Answer
No, Promise.race()
does not cancel the other promises that didn’t settle first.
This is an important behavior to understand. Once you’ve started a promise, it continues to run in the background, even if Promise.race()
has already settled.
This means if you’re using Promise.race()
to handle things like timeouts, you need to manually implement cancellation (if possible) to avoid wasted resources or unexpected side effects.
Why Does Promise Race Not Cancel the Other Promises?
The reason why Promise.race()
does not cancel other promises lies in how JavaScript promises work. Once a promise is initiated, there’s no built-in mechanism in the language to abort its execution.
Consider this:
const slowPromise = new Promise(resolve => setTimeout(() => resolve("Slow"), 5000));
const fastPromise = Promise.resolve("Fast");
Promise.race([slowPromise, fastPromise]).then(console.log);
Here, fastPromise
wins, but slowPromise
still runs for 5 seconds in the background.
Does Promise Race Cancel Promise? Implications for Real-World Code
Using Promise.race()
without considering cancellation can lead to:
- Memory leaks in long-running apps.
- Unwanted side effects, like unneeded API calls.
- Resource wastage, especially in environments like Node.js servers.
Let’s say you race a network request against a timeout. If the timeout wins, the request still continues unless you explicitly abort it using something like AbortController
.
Promise.race Only Resolves, Never Cancels
This is the foundation for understanding the focus question: does Promise race cancel promise? It simply listens for the first settled promise and then ignores the rest—but it doesn’t cancel them.
Use AbortController
for Manual Cancellation
To implement cancellation manually, use the AbortController
API.
const controller = new AbortController();
const fetchPromise = fetch('/api/data', { signal: controller.signal });
const timeout = new Promise((_, reject) => setTimeout(() => {
controller.abort();
reject(new Error('Timeout'));
}, 3000));
Promise.race([fetchPromise, timeout])
.then(response => console.log("Success", response))
.catch(err => console.error("Error", err));
This is the proper way to ensure that the losing promise (in this case, the fetch) doesn’t linger unnecessarily.
Learn more about AbortController
Does Promise Race Cancel Promise in Node.js?
Again, the answer is no. In environments like Node.js, the same rules apply. You must explicitly manage resource lifecycles, especially for file system operations, timers, or long-lived socket connections.
If you’re doing fs.promises.readFile()
in a race, the file read continues unless you take steps to interrupt it (which can be tricky).
Promise.race Is Great for Timeouts — But Be Careful
Timeout patterns using Promise.race()
are useful, but without cleanup, they become dangerous.
Uncancelled Promises Can Lead to Bugs
Especially in UIs or high-performance apps, a “losing” promise might still resolve or reject and cause undesired behavior if not handled.
Does Promise Race Cancel Promise? Common Misconceptions
Many developers think that using Promise.race()
is a silver bullet for timeouts or concurrent logic. But unless your other promises support cancellation, this assumption can lead to errors.
- Misconception: “The other promises are cancelled.”
- Reality: They’re just ignored by the
Promise.race()
return, but they still run.
Real-World Example: Cancel Fetch on Timeout
Here’s a real-world usage:
async function fetchWithTimeout(url, timeoutMs = 5000) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(url, { signal: controller.signal });
return await response.json();
} catch (e) {
throw e;
} finally {
clearTimeout(timeout);
}
}
This does what Promise.race()
alone cannot — it ensures proper cancellation.
There Are Libraries That Help
Some libraries provide cancellable promises or utilities that wrap Promise.race()
with more robust behavior. For example:
Cancellable Promises Aren’t Part of the Standard Yet
JavaScript doesn’t yet have native cancellable promises built-in, although proposals have existed. Until then, developers must use patterns like AbortController
.
Be Intentional With Your Async Design
Every time you use Promise.race()
, stop and ask: “Does Promise race cancel promise?” And more importantly, do I need to cancel it myself?
This mindset helps build safer and more predictable async code.
Final Thoughts: Does Promise Race Cancel Promise?
To summarize:
- No,
Promise.race()
does not cancel the losing promises. - Use
AbortController
or libraries to add cancellation support. - Don’t assume promises are stopped — they’re not.
- Understanding this behavior is critical for writing efficient and safe asynchronous code.
Leave a Reply