Cancel Promise pattern (no cancellable promises)

Bergi a.d.bergi at web.de
Fri Oct 28 12:39:41 UTC 2016


Jan-Ivar Bruaroey wrote:
> On 10/27/16 4:25 PM, Bergi wrote:
>> I'd however love to be able to cancel specific chaining operations,
>> i.e. `then` callbacks.
>
> If you try the fiddle - http://jsfiddle.net/jib1/jz33qs32/ - you'll see
> cancelling terminates the chain. If you intersperse non-cancellable
> operations, there'd be a delay if cancel is detected during those.

Yes, that's what I mean. Sure, I could use `Promise.race` to get the 
cancellation even if the non-cancellable operation resumes, but that's 
quite ugly:

Promise.race([
     promise()
     …chain…,
     cancelToken
]).then(callback);

especially when you'll need to nest that pattern. Instead, I'd just like 
to write

promise()
…chain…
.then(callback, cancelToken)

with the same behaviour.

>> A crucial problem that promises don't solve is synchronous inspection.
>> If my operation was cancelled, I'd like to know immediately (before
>> starting further work) about it, instead of waiting another tick
>> to be notified.
>
> I think it'd be odd to observe cancellation and not success nor failure,
> so this seems orthogonal.

I meant the producer would want to observer the cancellation so that he 
doesn't attempt to resolve the promise.

But yeah, observing cancellation vs success/failure is another problem 
that would benefit from inspection. Let's say I have a cancel token and 
a promise chain. Now I want to do exactly one of three different things, 
depending on what happens first: the operation is cancelled, the promise 
is rejected, or the promise fulfills. How do I do that?

>> But the fundamental problem with promises as cancellation tokens is
>> memory leaks. In your example, if the cancel button isn't clicked for
>> 10 seconds, the `token` promise will reference 3 `() =>
>> clearTimeout(id)` callbacks which close over their respective `id`s.
>> Three functions and three integer ids doesn't sound like much, but in
>> real applications with long-running un-cancelled operations a token
>> could accumulate quite an amount of resources which cannot be collected.
>> A clever programmer might make the callbacks become cheap no-ops, but
>> still at least the functions themselves will consume memory. For the
>> simple programmer, we need an automatic (not error-prone)
>> unsubscription mechanism once the respective cancellable operation ended.
>
> Thanks for the links. I think I'm in the camp of not being concerned
> about this. Recall I'm not proposing new functionality, just using
> promises, so this stands to benefit from optimizations browsers ought to
> make already, without needing special attention. Once browsers optimize:
>
>     function poll() { return isDone() || wait(1000).then(poll); }
>
> I'll worry about this. ;)

Yeah, I just think that we *need* new functionality (like the ability to 
remove callbacks from a promise) to solve cancellation properly.

It's true that ES6 has a bug that prevents implementors from optimising 
recursive assimilation, but it's a different kettle of fish to fix that 
in the spec. I'm trying to avoid that we make the same mistake again for 
cancellation tokens, so I think you *should* be concerned.

kind regards,
  Bergi


More information about the es-discuss mailing list