Allow yielding a chain of then on Task#950
Allow yielding a chain of then on Task#950SebastienGllmt wants to merge 2 commits intothefrontside:v3from
then on Task#950Conversation
| const newPromise = getHaltPromise().then(onfulfilled, onrejected); | ||
| const future: Future<NewResult> = create<Future<NewResult>>("Future", {}, { | ||
| *[Symbol.iterator]() { | ||
| return yield* call(() => newPromise); | ||
| }, | ||
| then: (...args) => newPromise.then(...args), | ||
| catch: (...args) => newPromise.catch(...args), | ||
| finally: (...args) => newPromise.finally(...args), | ||
| }); | ||
| return await future; |
There was a problem hiding this comment.
note: the code here for handling the abort future is mostly the same as the then in the parent Task
This is why I think maybe it's better if we have a more general way to create a Future that is exposed somewhere that is used in both these places
There is, to some extent, a conceptual overlap between what this block of code is trying to do and what call is doing. That is to say, if call returned a Future instead of an Operation, using it here could also be an option
| /** | ||
| * Attaches callbacks for the resolution and/or rejection of the Promise. | ||
| * @param onfulfilled The callback to execute when the Promise is resolved. | ||
| * @param onrejected The callback to execute when the Promise is rejected. | ||
| * @returns A Promise for the completion of which ever callback is executed. | ||
| */ | ||
| then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Future<TResult1 | TResult2>; | ||
|
|
||
| /** | ||
| * Attaches a callback for only the rejection of the Promise. | ||
| * @param onrejected The callback to execute when the Promise is rejected. | ||
| * @returns A Promise for the completion of the callback. | ||
| */ | ||
| catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Future<T | TResult>; | ||
|
|
||
| /** | ||
| * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The | ||
| * resolved value cannot be modified from the callback. | ||
| * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). | ||
| * @returns A Promise for the completion of the callback. | ||
| */ | ||
| finally(onfinally?: (() => void) | undefined | null): Future<T>; |
There was a problem hiding this comment.
Note: these three are copy-pasted from the definition of Promise, but have the return type changed from Promise → Future
| }); | ||
| } | ||
| }, | ||
| then: (...args) => getHaltPromise().then(...args), |
There was a problem hiding this comment.
Note: there is one very subtle change introduced by this PR: the result of these is no longer a Promise and, instead, is now a PromiseLike. In practice, this should work everywhere (the goal of PromiseLike is that they're meant to be supported by everything magically), but it is possible to write code that only works on Promises and not PromiseLike (ex: any code that uses instanceof Promise)
|
I'm wondering about the corner cases here.
I.e. what would be the expectation around this: run(fn).then(function*(value) { return value + 1 }) |
You could say that may we would like |
|
This should be addressed by #1065 and thefrontside/effectionx#112 Please let us know if there is anything we missed. |
Motivation
There are cases where you need to do the following steps:
Task(usingrun)Taskusingthenyieldthe result of the taskexample that shows how this can be used to:
Promiseto FAQ #946 without requiring to useasync/awaitexplicitly anywherecallas in Add equivalent toPromise.thento FAQ #944This was a bit tedious to do previously (see #944), and this PR simplifies this case a bit by making that calling
thenon aTaskreturns aFuture(which you can yield) instead of just aPromiseApproach & Alternate Designs
You can find some background in #944 and inline comments in this PR
TODOs and Open Questions
Futures more easier in general? This has a chance of overlapping conceptually with thepipeconcept that was recently removed, and also overlaps with the idea ofcall(althoughcallreturns anOperationinstead of aFuture)thenreturns aTaskinstead of aFuture? I tried this initially, but ran into some complications: Add equivalent toPromise.thento FAQ #944 (comment)