promise-cancellation icon indicating copy to clipboard operation
promise-cancellation copied to clipboard

CancelToken-likes?

Open bergus opened this issue 9 years ago • 5 comments

The Promise constructor takes a cancellation token argument (and lots of other API functions take one and pass it through to the promise constructor). But what exactly should one be able to pass in there?

  • instances of CancelToken: sure
  • instances of CancelToken subclasses: probably
  • arbitrary objects as long as they have a .requested property: maybe, why not?

Actually a .requested property is not exactly enough. We need a way to register a function that synchronously cancels the promise when the cancellation is requested. In the current proposal, RegisterPromise, CancelPromise and CancelFunction take care of this. This also works for CancelToken subclasses, as they do have a [[RegisteredPromises]] slot as well.

And with .requested properties we need to be cautious too. Currently it is expected that it changes state exactly only once, from false to true, and that when it does that happens in the process of calling CancelFunction. This ensures that we have no pending promises whose [[CancelToken]] is .requested, and that we have no cancelled promises whose [[CancelToken]] is not .requested. (Or at least not observably to scripts, the first situation actually happens during the call to CancelFunction). This already breaks apart for subclasses of CancelToken, who can overwrite get requested() at their own discretion. For those instances, we can actually check their [[Result]] directly like CancelToken.prototype.requested does, to ensure that we don't believe in .requested when it claims false despite the token being cancelled (see also #7 for related issues). This is not easily possible for arbitrary objects however.

bergus avatar Jul 22 '16 08:07 bergus

The next question, after deciding what is a cancellation token, is what the constructor should do when something was passed but it's invalid. The default would be do nothing, but I guess we could as well assume that anything (non-null, non-undefined) being passed as a second argument is supposed to be a token, and when it is invalid we could throw (ending up as rejection) before calling the executor.

bergus avatar Jul 24 '16 16:07 bergus

Doing anything besides "do nothing" would be a breaking change, since there are definitely existing scripts that return values in the executor.

ljharb avatar Jul 24 '16 16:07 ljharb

@ljharb But I don't know any scripts that pass something token-like as an argument besides the constructor. Of course it is a breaking change to introduce a second parameter, but I don't think it'll break anything.

bergus avatar Jul 24 '16 16:07 bergus

https://github.com/tc39/proposal-cancellation/issues/22 looks like a step forward in this direction

bergus avatar Aug 14 '18 20:08 bergus

With https://github.com/tc39/proposal-cancellation/issues/22, I would liken this to the behavior of new Map([]) vs. new Map({}). Since {} doesn't have a Symbol.iterator method, a TypeError would be thrown. However new Map(), new Map(undefined), and new Map(null) do not throw as the argument is ignored. The same would be the case for an object expected to have a Symbol.cancelSignal method.

rbuckton avatar Aug 14 '18 23:08 rbuckton