W3C home > Mailing lists > Public > public-script-coord@w3.org > January to March 2015

Re: Cancellation architectural observations

From: Frankie Bagnardi <f.bagnardi@gmail.com>
Date: Sun, 29 Mar 2015 10:10:51 -0700
Message-ID: <CADw0yCyu2XxYBHtSQhD1rJrZyMufbVFoy4UFf6xZeME7qXORaw@mail.gmail.com>
To: Andrea Giammarchi <andrea.giammarchi@gmail.com>
Cc: Ron Buckton <Ron.Buckton@microsoft.com>, es-discuss <es-discuss@mozilla.org>, "public-script-coord@w3.org" <public-script-coord@w3.org>
I don't think this has been brought up, but isn't what we're doing here
bubbling an event?  Would it make sense to generalize this to a simple
event bubbling system?

function cancelableGet(url){
  const xhr = new XMLHttpRequest();
  return new Promise(function(resolve, reject){
    xhr.open('get', url);
    xhr....

    this.on('cancel', reason => {
      xhr.abort();
      reject(new CanceldRequest(reason));

      // if we wanted to pass it upwards
      this.emit('cancel', reason);
    });
  });

}

cancelableGet('/foo')
.then(...)
.emit('cancel');

‚Äč

Our listener would be unbound as soon as the promise in cancelableGet settled.


This also allows for non-overlapping names for events (Symbol should be
permitted), where there may be multiple cancelable things in the chain.

It also allows additional metadata, or different event names when 'cancel'
can mean multiple things.  For example, a process.  Do we send sigint or
sigkill to cancel it?

Thoughts?



On Sun, Mar 29, 2015 at 8:56 AM, Andrea Giammarchi <
andrea.giammarchi@gmail.com> wrote:

> OK, just for record sake, I'v ecreated a working example of what I
> previously meant.
> https://gist.github.com/WebReflection/a015c9c02ff2482d327e
>
> Here a basic example (something that will reject on timeout)
> ```js
>
> // will be resolvednew Promise(function ($res, $rej, ifCanceled) {
>   var internal = setTimeout($rej, 1000);
>   ifCanceled(function () {
>     clearTimeout(internal);
>   });
> })// will be resolved without executing
> .then(
>   function () {
>     console.log('on time');
>   },
>   function () {
>     console.log('error');
>   }
> )
> .cancel()// will simply execute and resolve
> .then(function () {
>   console.log('no time');
> });
>
> ```
>
> The idea is that a Promise is cancelable **only** if a function that
> defines how to cancel is provided, otherwise there's no cancel-ability,
> it's a regular Promise, and nothing is exported.
>
> This still grants internal private/hidden cancelability through a
> resolution or rejection but it also gives the ability to expose a
> `.cancel()` to the outher world.
>
> There's no "forever pending" problem because all Promises involved in the
> chain will be silently resolved.
> The code might be a bit convolute but it was mainly to provide a
> playground and I don't see any real violation of the Promises principles.
>
> The presence of `cancel` and its ability is a contract between the Promise
> creator/provider and the external world.
>
> Best Regards
>
>
>
> On Fri, Mar 27, 2015 at 5:43 PM, Andrea Giammarchi <
> andrea.giammarchi@gmail.com> wrote:
>
>> following up from this
>> https://github.com/whatwg/fetch/issues/27#issuecomment-86987752 , and
>> most likely late to the party.
>>
>> How about cancel-ability done this way ?
>>
>> ```js
>>
>> var p = new Promise(function (res, rej, cancel) {
>>   // resolved in 1 second via random value
>>   var t = setTimeout(res, 1000, Math.random());
>>   // if meant to be canceled
>>   // we define internally what to do
>>   cancel(function () {
>>     clearTimeout(t);
>>   });
>> });
>>
>> // whenever/if needed
>> p.cancel().then(...);
>> ```
>>
>> The exposed cancel-ability is arbitrary provided internally so that if
>> missing, an error is thrown while if provided it sets the internal state of
>> the promise as `canceled` in case it's different from `resolved` or
>> `rejected`
>>
>> It gives the ability to react, if a `then` is attached, or the ability to
>> ignore, if nothing happens to the returned, non cancel-able, Promise.
>>
>> This avoids exposing to the outer world what happens inside the Promise
>> and provides arbitrary ability to cancel one.
>>
>> A cancel-able Promise is one that defined such behavior, which by default
>> is throwing if that's not defined internally.
>> This would solve already many cases I have in mind, via users, or
>> UserAgent, and legitimately behind the scene without any need to expose any
>> internal logic.
>>
>> How to resolve or throw other attached promises? Well,
>> `p.cancel().then()` resolves, while `p.cancel().throw()` does not.
>> `p.cancel()`, without then or throw would simply throw away pending
>> promises as explicit `ignore` intent.
>>
>> How bad does it look and what am I screwing up in here in terms of
>> Promises philosophy?
>>
>> Best Regards
>>
>>
>>
>>
>>
>>
>>
>> On Wed, Mar 4, 2015 at 8:01 PM, Ron Buckton <Ron.Buckton@microsoft.com>
>> wrote:
>>
>>> > new Promise(resolve => doLater(resolve, cts.token)).then(handleResult);
>>> > setImmediate(() => cts.cancel());
>>>
>>> >
>>> > In this scenario cancel would be called right after the resolve method
>>> > is called, but before handlerResult is called. For this to work with a
>>> > cancellation token you would need to pass the token to every step in
>>> > the chain to both stop work being done and to ignore the
>>> > result/prevent a handler from being called. Wouldn't it be better if
>>> > the promise chain took care of this for the programmer?
>>>
>>> I can be convinced that CancellationToken registrations should be
>>> invoked asynchronously, though I wonder if then
>>> CancellationTokenSource#cancel should return a Promise to observe any
>>> errors that occur.
>>>
>>> Ron
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss@mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
>>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
Received on Sunday, 29 March 2015 17:11:39 UTC

This archive was generated by hypermail 2.3.1 : Sunday, 29 March 2015 17:11:39 UTC