You can't cancel a JavaScript promise (except sometimes you can)

goodoldneon 81 points 53 comments April 07, 2026
www.inngest.com · View on Hacker News

Discussion Highlights (15 comments)

dimitropoulos

> Libraries like Effect have increased the popularity of generators, but it's still an unusual syntax for the vast majority of JavaScript developers. I'm getting so tired of hearing this. I loved the article and it's interesting stuff, but how many more decades until people accept generators as a primitive?? used to hear the same thing about trailing commas, destructuring, classes (instead of iife), and so many more. yet. generators still haven't crossed over the magic barrier for some reason.

game_the0ry

Off topic, but that site has really nice design

pjc50

I like how C# handles this. You're not forced to support cancellation, but it's strongly encouraged. The APIs all take a CancellationToken, which is driven by a CancellationTokenSource from the ultimate caller. This can then either be manually checked, or when you call a library API it will notice and throw an OperationCancelledException. Edit: note that there is a "wrong" way to do this as well. The Java thread library provides a stop() function. But since that's exogenous, it doesn't necessarily get cleaned up properly. We had to have an effort to purge it from our codebase after discovering that stopping a thread while GRPC was in progress broke all future GRPC calls from all threads, presumably due to some shared data structure being left inconsistent. "Cooperative" (as opposed to preemptive) cancel is much cleaner.

cush

GC can be very slow. Relying on it for control flow is a bold move

eithed

> Promise itself has no first-class protocol for cancellation, but you may be able to directly cancel the underlying asynchronous operation, typically using AbortController. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

mohsen1

Back in 2012 I was working on a Windows 8 app. Promises were really only useful on the Windows ecosystem since browser support was close to non existent. I googled "how to cancel a promise" and the first results were Christian blogs about how you can't cancel a promise to god etc. Things haven't changes so much since, still impossible to cancel a promise (I know AbortSignal exists!)

abraxas

and so the thirty year old hackathon continues...

afarah1

You can also race it with another promise, which e.g. resolves on timeout.

thomasnowhere

The never-resolving promise trick is clever but what caught me off guard is how clean the GC behavior is. Always assumed hanging promises would leak in long-lived apps but apparently not as long as you drop the references.

bastawhiz

Be careful with this, though. If a promise is expected to resolve and it never does, and the promise needs to resolve or reject to clean up a global reference (like an event listener or interval), you'll create a memory leak. It's easy to end up with a leak that's almost impossible to track down, because there isn't something obvious you can grep for.

shadowgovt

I soft of feel like every five years someone comes along and tries to re-invent cancellable threads and immediately arrives back at the same conclusion: the problem of what it means to "cancel" a thread is so domain-specific that you never save anything trying to "support" it in your threading framework; you try and save people the effort of doing something ad-hoc to simulate cancellation and build something at least as complicated as what they would build ad-hoc, because thread cancellation is too intimately tied to the problem domain the threads are operating on to generalize it.

littlestymaar

Ten years ago, I was an acid reader of the tc39 (EcmaScript standard committee) mailing list and cancelable promises used to be the hot topic for a while. I unsubscribed at some point because I wasn't working with JavaScript this much, but it's disappointing to see that this work has gone nowhere in the meantime. I like how Rust futures are canceled by dropping them, even though it's also a footgun (though IMHO this is more of a problem with the select! pattern than with drop-to-cancel proper).

cowboyd

Is it safe to just "stop calling next() on a generator?" like the post suggest? To me that sounds like dropping the task on the floor. Specifically, this will not invoke any finally {} blocks: More correctly, you should invoke `return()` on the generator. Otherwise, you won't provide execution guarantees. This is how Effection does it. There is no equivalent in async functions, so it sounds like the same problem would apply to the GC technique.

notnullorvoid

The argument against rejecting to cancel seems like a stretch to me. It's completely fine if you view cancellation as a error condition, it allows you to recover from a cancellation if you want (swallow the error w catch) or to propagate it.

stevefan1999

I would also argue that Rust failed to cancel a Future too, considering I came from a C++ and C# background where I know a lot more about async/await and the missing of "cancellation token" in Tokio is so infuriating. I have to came all the way to attach it to a Future, that because Rust doesn't have any default argument, I mean I have to supply cancellation token from the top to bottom. But in hindsight, Golang's context actually do mimick cancellation token in some sort, but in a way that the cancellation is cascaded and recursive by using done in canceler or deadline which means it is timing and latency sensitive. If you truly want cancellation token style, you need to use semaphores or by explicitly polling the cancellation channel (which is what you can do with context) which can hurt if you don't have enough thread slack.

Semantic search powered by Rivestack pgvector
3,871 stories · 36,122 chunks indexed