Um... This isn't much different than Bluebird's `Promise.prototype.cancel`, admittedly the least optimal of all these so far.
On Sat, Jan 7, 2017, 08:02 Igor Baklan <io.bak...@gmail.com> wrote: > In general I thing it would be good to have something like > [``java``(``Thread.interrupt()``)]( > https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#interrupt()), > assuming that "Thread" here can be "async stacktrace of promises", and > interrupt notification should be just forwarded to top entry > ([promise-executor]( > https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Parameters)) > and handled there arbitrary. In meta code it can be approximately expressed > like ``promise.interrupt(interruption_config)`` ==> > ``promise.topPromiseInAwaitChain().injectInterruptionNotification(interruption_config)``. > So it should be up to [promise-executor]( > https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Parameters) > - whether it want to complete abnormally on interruption (either with > success or with failure), or just ignore this signal and continue execution > without any reaction. It just assumes that general ``.then(...)``-like > promises or ``async (...) => {...}``-like promises should propagate > interruption-signal transparently upward over async-stacktrace, and > interruption-signal would be handled only in promises with executors which > aware of interruption capability. In code it may look like > > ```js > const waitAsync = (delay) => (new Promise( > (resOk, resErr, interuptionSignalEmitter) => { > const beforeComplete = () => {clearTimeout(tid);} > const tid = setTimeout( > () => {beforeComplete(); resOk();}, > delay > ); > interuptionSignalEmitter.on( > (interuptionConfig) => { > beforeComplete(); > if (interuptionConfig && interuptionConfig.raiseError) { > resErr(new Error("abnormal interuption")); > } else { > resOk(); > } > } > ); > } > )); > > // waitAsync(100).then(() => {console.log("wait ok")}).interrupt() - > should complete successfully > // ("wait ok" message should be printed) but without delay in 100ms > // waitAsync(100).then(() => {console.log("wait > ok")}).interrupt({raiseError: true}) - should complete with failure > // (NO "wait ok" message should be printed) and without delay in 100ms > ``` > > > So, in other words, I would rather say, that we lack something like event > capturing pahase when we intent for abnormal-completion/cancellation. I > mean, if we have for example some async-stacktrace and some particular > entry in it in the middle (some running and not yet completed promise), > then it looks very natural that we may wish to "send a signal/message" > downward over async-stacktrace, it just can be made by throwing something > in that entry (and that "thrown something" will be naturally propagated > downward async-stacktrace/promises-chain). But in certain cases we may need > to "send a signal/message" upward over async-stacktrace which should > generally end up by handling in very top promise executor (and if that > top-most promise in chain decide to complete execution abnormally, then all > clean-up in promises-chain also happens "abnormally"), while if we just > "unsubscribe" some middle entry form it's "natural parent" and "abnormally" > assign some result to that entry, then ofcourse, all cleanup in "upper > part" of async-stacktrace will happen later (which ofcourse also can be > desired behavior in some cases). > > Jan-Ivar Bruaroey wrote: > > Because it doesn't make fetch stop fetching, which is what people want > > as I understand it (to not have the fetch keep going even though they've > stopped waiting for it). > > Completely agree, but I would rather prefer > > ```js > fetch(someUrl, someConfig).interuptOn(interruptionToken) > ``` > vs > ```js > fetch(someUrl, {...someConfig, cancel: interruptionToken) > ``` > in this case ``.interruptOn`` can be easily defined on top of > ``.interrupt`` like ``promise.interruptOn(interruptionReasonToken)`` <==> > ``interruptionReasonToken.then((reason) => {promise.interrupt(reason)}), > promise`` > > > Bergi wrote: > > 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. > > Very reasonable. left-to-right ``.`` chaining is much more readable and > concise then wrap-like expression chaining. > But I would rather put ``cancelToken`` somewhere else, not in ``.then`` > call. > From my perspective it can look like > > ```js > Promise.race([ > promise() > …chain…, > cancelToken > ]).then(callback); > ``` > <==> > ```js > promise() …chain… cancellable().cancelOn(cancelToken).then(callback); > ``` > Where ``Promise::cancellable`` (``Promise.prototype.cancellable``) can > return some sort of "wrapper" - ``CancellablePromise(targetPromise)`` > which in turns can be implemented based on ``Promise.race([targetPromise, > CancellablePromise::privateInternalCancelToken])`` and that > ``privateInternalCancelToken`` can be fully controlled by > ``CancellablePromise`` itself and completed(fulfilled/rejected) when ever > it needed (whether by direct call to > ``cancellablePromise.completeNow(...)`` or caused by completion of some > promise passed to ``.cancelOn`` method) > > And finally > > Bergi wrote: > > I'd however love to be able to cancel specific chaining operations, > > i.e. `then` callbacks. > > As for me, definitely such kind of possibility should be available. > However we can not unsubscribe ``then``-callback same easily as regular > event handler. Since at least [some sort of ``finally``-callbacks]( > https://www.npmjs.com/package/promise.prototype.finally) should always > work on any item in remaining promises chain. So promise > then-unsubscription is tightly bound to providing immediate completion > result for that target promise (which would be used instead of callback > invocation result). And still it can be accomplished by some kind of > third-party solutions, (like in snippets above) like > ``promise.cancellable().then(() => > {doSomth()}).completeImmediately({error:new Error("unsubscribed > abnormally")})``. If ``.cancellable()`` returns some wrapped instance like > ``CancellablePromise(targetPromise)`` then ofcourse ``CancellablePromise`` > can re-implement ``.then``, ``.catch``, etc by wrapping passed functions > and by wrapping ``targetPromise.then(...wrappedCallbacks)`` with > appropriate ``Promise.race([...])`` like > ``Promise.race([targetPromise.then(...wrappedCallbacks), > internalCancellationToken])``, and then when ``.completeImmediately`` > invoked coordinate appropriately wrapped callbacks and > ``internalCancellationToken`` to prevent initial callbacks from being > executed and to complete "overall resulting promise" by the means of > ``internalCancellationToken``. > But. I think disregarding that all of this stuff can be (more or less) > implemented in 3-rd parity libraries, it would be much better if it was > supported natively. > _______________________________________________ > 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