-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft D: Cancellation Token+ #11
Comments
going by promises-aplus/cancellation-spec/issues/11: CancellationToken+ * it's not as ugly as the TokenSource on master branch but I still feel that it should be even less ugly * changed .fork() signature to take an object which also can have a .token and an .assimilate callback attached - cancelling handlers of resolved promises is buggy + implemented a .send(message) pipeline * which is used for cancellation attempts relatively dry because of a 5-parameter addCancellationSend function * timer methods, .all, .race have not yet been adapted.
It's still a bit difficult to undersand how it works. Can you see if this the code below demonstrate the full scenario?
|
Hi, thanks for your interest (after such a long time :-) - I had to re-read the draft myself). So let's step through your code:
So far so good. Notice that
Yes. You've passed an explicit token, which is associated with
No. Neither handler is executed yet,
No. As you haven't passed any token, a new implicit token is created that is associated with
Not necessarily. There is no associated token, yes, but that doesn't mean it's automatically cancelled.
Yes,
No. With
Yes, If these results seem queer, notice that the explicit cancellation token is only a tool for explicit control over the cancellation process (which might be supplied by the user). Most usages of this proposal will rely on the implicitly created cancellation tokens that will get automatically revoked when there are no more handlers. |
Thanks so much for your time to walk me through. I'm a bit more understood there. With a few more questions :).
Why does it need to register the cancellation token with the paren promise,
Why do we need to supply a
I think it would be more intuitive if cancelling a promise actually revoke the cancellationToken associated with it? i.e. without the second parameter. How do you think? |
Because that is the most important purpose of the tokens: registering a token together with one or two handlers signals to the promise that someone is interested in its result. Cancelling this token later signals the disinterest - the handlers shall be removed and never be executed.
To distinguish cancellations from other causes that prevented the promise from completing normally.
Possibly, if step 4 is un-bracketed - I'm not sure about this.
Yes, that's the default behaviour for implicit cancellation tokens - you will never see them. The |
Thanks for explanation, that help me clarified a lot of things! @bergus The part I like the most is the extension to the promise/A+ Initially, I feel that using the token would be easy to understand. However, after I tried the usage it seems that the down said is the code readability that's it's not intuitive to know which promise and it's pending task is being involved due to chained promise. Or how when to supply a token or not. I have idea to simplify that other than token tho, I will share it in a separate thread as another proposal. Hope you don't mind. |
I've reworded, clarified and detailed the draft now, you can find it in this gist. |
going by promises-aplus/cancellation-spec/issues/11: CancellationToken+ * it's not as ugly as the TokenSource on master branch but I still feel that it should be even less ugly * changed .fork() signature to take an object which also can have a .token and an .assimilate callback attached - cancelling handlers of resolved promises is buggy + implemented a .send(message) pipeline * which is used for cancellation attempts relatively dry because of a 5-parameter addCancellationSend function * timer methods, .all, .race have not yet been adapted.
I really love the idea of cancellation tokens from #8. However, I will go even further and amend/modify the specification for
then
, so that handlers themselves can be prevented from execution.Terminology
CancellationToken
is an object with methods for determining whether an operation can be cancelled.CancellationToken
might be associated with a promise.CancellationToken
s can be registered with a promise.CancellationError
is an error used to reject cancelled promises.CancellationError
.CancellationToken
that is in the cancelled state, denoting that the result of the operation is no longer of interest. It might be considered an unregistered token or a revoked token.onFulfilled
oronRejected
argument to a.then()
call whosecancellationToken
has been revoked.Requirements
The
then
methodExtensions are made to the following sections:
2.2.1. If
onFulfilled
is a function:2.2.1.1. it must be called _unless it is cancelled_ after
promise
is fulfilled, withpromise
’s value as its first argument.2.2.2.1. If
onRejected
is a function,2.2.2.2. it must be called _unless it is cancelled_ after
promise
is rejected, withpromise
’s reason as its first argument.Note: 2.2.1.3. and 2.2.2.3. ("must not be called more than once") stay in place, and still at most one of the two is called.
2.2.6.1. If/when
promise
is fulfilled, all respective _uncancelled_onFulfilled
callbacks must execute in the order of their originating calls tothen
.2.2.6.2. If/when
promise
is rejected, all respective _uncancelled_onRejected
callbacks must execute in the order of their originating calls tothen
.2.2.7.3. If
onFulfilled
is not a function andpromise1
is fulfilled _andpromise2
was not cancelled,promise2
must be fulfilled with the same value aspromise1
.2.2.7.4. If
onRejected
is not a function andpromise1
is rejected _andpromise2
was not cancelled,promise2
must be rejected with the same reason aspromise1
.(we probably need these last two in every cancellation spec anyway)
The
CancellationToken
A
CancellationToken
is an object with a unique identity. It can get revoked, moving it into the cancelled state, which is an irreversible change.The object has an
isCancelled
property, whose value must be a boolean[, or a function that returns a boolean]. It must yieldtrue
if the token is in the cancelled state, andfalse
otherwise.Retrieving the state of a cancellation token must not change the state, i.e. an
isCancelled
function must have no side effects.The
CancellationError
Error
(cancellationError instanceof Error === true
).name
property with value"CancellationError"
.cancelled
property with valuetrue
.The
cancellationToken
parameterThe fourth parameter of the
then
method is an optionalcancellationToken
; a call does look likeIf
cancellationToken
is not aCancellationToken
object, create an implicit CancellationToken for the newpromise
. In both cases (explicit and implicit) associate it with the newpromise
. The state of an explicit token must not be changed by thethen
method.Register this cancellation token with the
parentPromise
.Also register this cancellation token with any
child
promises that are returned fromonFulfilled
oronRejected
(2.2.7.1). This includes passing the cancellation token to thethen
call in step 2.3.3.3. of the Promise Resolution Procedure.If the
promise
is attempted to be cancelled with anerror
, run the following steps:parentPromise
is pending, attempt to cancel it witherror
.onRejected
is a function and neither it noronFulfilled
have been called, execute it with theerror
as its argument. (with 2.2.4. "async execution", and 2.2.7.1. "assimilation" in mind)]onFulfilled
oronRejected
have been called and returned achild
promise, attempt to cancel that witherror
.onRejected
will not be executed]], rejectpromise
witherror
.The
cancel
methodThe
cancel
method of a promise accepts two optional parameters:promise
is still pending. Returnfalse
otherwise.reason
is aCancellationError
, leterror
be that error object, else leterror
be a newCancellationError
with thereason
as the value of itsmessage
property.token
is aCancellationToken
, revoke it.promise
witherror
.The
Promise
constructorPromises not created by a call to
then
may handle attempts to cancel them in implementation-dependent ways.Constructors are however encouraged to signal these to the promise creators, and optionally provide them access to the list of registered tokens. This might be done through a callback that is passed as an additional argument to the
Promise
constructor, or returned from theresolver
call.Pluses:
no ambiguity when a promise is cancelled before the handlers of its resolved parent could be executed
making a promise uncancellable is trivial:
.then(null, null, null, {isCancelled:false})
forking a promise (to prevent immediate cancellation) is even more trivial:
.then()
Minus:
finally
in terms of.then()
without preventing cancellation - it is not possible to add a handler via calling.then()
without registering a token.The basic idea of this draft is that handlers that were passed to
then
will not be executed when the cancellation token that accompanied them is cancelled:I'm not so sure about the steps 4 and 6 of cancellation attempts.
effectshandlers, notice that all forks/branches have beencutcancelled so it's a linear chain). For discussion, see issue Cancel every promise in the chain, or only the deepest cancellable ancestor? #10.The text was updated successfully, but these errors were encountered: