- From: Andrea Giammarchi <andrea.giammarchi@gmail.com>
- Date: Mon, 2 Mar 2015 21:18:57 +0000
- To: Ron Buckton <rbuckton@chronicles.org>
- Cc: Dean Tribble <tribble@e-dean.com>, Kevin Smith <zenparsing@gmail.com>, "public-script-coord@w3.org" <public-script-coord@w3.org>, es-discuss <es-discuss@mozilla.org>
- Message-ID: <CADA77mgemV2iqaGjgGUAF9RGyR7sOXo545RgCrZhZP1ncV2cmw@mail.gmail.com>
So this is my simplified view of the matter ... it already works, and it
aborts eventually with the ability to ignore the onabort callback.
The config object can have `onabort` that activates the "abort-ability",
the `onprogress` so that eventually this promise inside a generator can
still update UIs, and potentially any other sort of property but for demo
sake just `method` for GET, HEAD, PUT, POST and other requests.
```js
function fetch(url, config) {
config || (config = {});
var
xhr = new XMLHttpRequest,
promise = new Promise(function (res, rej) {
xhr.addEventListener('error', function (pe) { rej(xhr); });
xhr.addEventListener('load', function (pe) { res(xhr); });
if (config.onabort)
xhr.addEventListener('abort', config.onabort);
if (config.onprogress)
xhr.addEventListener('progress', config.onprogress);
xhr.open(config.method || 'GET', url, true);
xhr.send(null);
})
;
if (config.onabort)
promise.abort = xhr.abort.bind(xhr);
return promise;
}
```
abort example:
`fetch('?page', {onabort: console.warn.bind(console)}).abort();`
with progress too
`fetch('?page', {onabort: console.warn.bind(console), onprogress:
console.log.bind(console)}).abort();`
full request
`fetch('?page', {onabort: console.warn.bind(console), onprogress:
console.log.bind(console)}).then(console.log.bind(console));`
Why this code? Simply to somehow show that I am all for getting this right,
but to me it's also probably a simpler matter than it looks like, specially
for cases where cancel or abort is meant and needed.
Best Regards
On Mon, Mar 2, 2015 at 7:45 PM, Ron Buckton <rbuckton@chronicles.org> wrote:
>
>
> In light of *Async Functions* in ES7, it may make sense to separate the
> abstractions between promises and cancellation. Promises and cancellation
> signals have different use cases:
>
>
> *Promises*
>
> - Promises are *consumed* by the caller and *produced* by the callee.
> - Observation a promise resolution can only happen in a *later * turn.
> - The consumer of a promise *cannot* directly resolve the promise.
>
> *Cancellation*
>
> - Cancellation signals are *produced* by the caller and * consumed* by
> the callee.
> - Observation a cancellation signal must happen *immediately*.
> - The consumer of a cancellation token *cannot* directly cancel the
> token.
>
> *API Proposal:*
>
>
> class CancellationTokenSource {
> /** Create a new CTS, optionally with an iterable of linked cancellation
> tokens. */
> constructor(linkedTokens?: Iterable<CancellationToken>);
>
> /** Gets the cancellation token for this source. */
> get token(): CancellationToken;
>
> /** Cancels the source and sends a cancellation signal with an optional
> reason (default Error("Operation canceled")). */
> cancel(reason?: any): void;
>
> /** Cancels the source after a delay (in milliseconds), with an optional
> reason. */
> cancelAfter(delay: number, reason?: any): void;
>
> /** Prevents any possible future cancellation of the source and removes
> all linked registrations. */
> close(): void;
> }
>
> class CancellationToken {
> /** Gets a cancellation token that can never be canceled. */
> static get default(): CancellationToken;
> /** Gets a value indicating whether the cancellation signal was sent. */
> get canceled(): boolean;
> /** If canceled, gets the reason for cancellation if provided;
> otherwise, returns `undefined`. */
> get reason(): any;
> /** If canceled, throws either the reason or a general “Operation
> Canceled” error. */
> throwIfCanceled(): void;
> /**
> * Registers a callback to execute immediately when a cancellation
> signal is received.
> * The callback can be removed using the `unregister` method of the
> return value.
> */
> register(callback: (reason: any) => void): { unregister(): void };
> }
>
>
> *Usage (Abort):*
>
>
> ```
> // aborts and throws error when canceled
> function fetchAsync(url, cancellationToken = CancellationToken.default) {
> return new Promise((resolve, reject) => {
> cancellationToken.throwIfCanceled();
> var xhr = new XMLHttpRequest();
> var registration = cancellationToken.register(() => xhr.abort());
> xhr.open("GET", url, /*async*/ true);
> xhr.onload = event => {
> registration.unregister();
> resolve(xhr.responseText);
> };
> xhr.onerror = event => {
> registration.unregister();
> reject(xhr.statusText);
> }
> xhr.send(null);
> });
> }
>
> fetchAsync(...).then(...); // as expected
>
> var cts1 = new CancellationTokenSource();
> fetchAsync(..., cts1.token).catch(...);
> cts1.cancel(new Error("Operation Canceled"); // .catch gets the error and
> the xhr is aborted.
>
>
> *Usage (Ignore):*
>
>
> // ignore operation/stop processing
> async function startTicker(receiveSymbol, cancellationToken =
> CancellationToken.default) {
> while (!cancellationToken.canceled) {
> var symbols = await fetchSymbols();
> for (var symbol of symbols) {
> receiveSymbol(symbol);
> }
> }
> }
>
> var stopTicker = new CancellationTokenSource();
> stopTicker.cancelAfter(5 * 60 * 1000); // stop after 5 minutes.
> startTicker(..., stopTicker.token).catch(...); // .catch only gets error
> from `fetchSymbols`.
>
>
> Ron
> ------------------------------
> *From:* es-discuss <es-discuss-bounces@mozilla.org> on behalf of Dean
> Tribble <tribble@e-dean.com>
> *Sent:* Monday, March 02, 2015 1:25 PM
> *To:* Kevin Smith
> *Cc:* public-script-coord@w3.org; es-discuss
> *Subject:* Re: Cancellation architectural observations
>
> On Mon, Mar 2, 2015 at 6:32 AM, Gray Zhang <otakustay@icloud.com> wrote:
>
>> +1 to the ignore term, I’ve opened an issue about it in
>> https://github.com/promises-aplus/cancellation-spec/issues/14
>>
> I have little attachment to any term, but there's value in keeping
> terminology that has years of investment and use in other contexts. However
> "ignore" also has the wrong sense, because it implies that the computation
> completes anyway. That can be accomplished more easily by simply dropping
> the promise.
>
>> IMO the term cancel(or abort) and ignore are totally different things,
>> the former one means “do not continue, stop it right now” and the “stop”
>> state should be broadcast to everyone who is interested in the work, while
>> the latter means “I don’t care about the result anymore, just play it as
>> you like”, it means the async progress can be continued
>>
> This goes back to some of the observations above: you cannot stop it
> "right now" because async notification is not synchronous; indeed the
> operation may already be complete before you stop it. Thus consumers of the
> result of a cancellable request need to be able to handle either successful
> completion or the cancelled state (which just looks like any other error
> that prevented completion). Attempting broadcast to "everyone" adds
> complexity and resources that are needed only in the rare cancellation
> case. It's typically not only not worth the software complexity, but not a
> good idea. When you cancel a print job, the document editor should make
> best efforts in the background to stop requesting fonts, stop laying out
> print pages, stop spitting out pages on the printer, etc. but most
> importantly, it should start paying attention to my new edits and hang
> waiting for everything that might be involved in printing to wrap itself up.
>
>> In practice both scenario are commonly seen, we may abort a resource
>> fetch in order to save bandwidth and opened connections, or we may in other
>> side just ignore it since continue to complete the fetch can result in a
>> local cache, which speeds up our fetch next time
>>
> The resource point is important. That's the "don't care" scenario, not the
> "abort" scenario. It's the request processor that knows what cleanup is
> worth the effort. The initiator of the request only knows they don't care
> about the result anymore.
>
> _______________________________________________
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
Received on Monday, 2 March 2015 21:19:24 UTC