-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow yielding a chain of then
on Task
#950
base: v3
Are you sure you want to change the base?
Conversation
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: these three are copy-pasted from the definition of Promise
, but have the return type changed from Promise
→ Future
@@ -86,10 +115,37 @@ export function createTask<T>( | |||
}); | |||
} | |||
}, | |||
then: (...args) => getHaltPromise().then(...args), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
Motivation
There are cases where you need to do the following steps:
Task
(usingrun
)Task
usingthen
yield
the result of the taskexample that shows how this can be used to:
Promise
#946 without requiring to useasync/await
explicitly anywherecall
as in Document equivalent toPromise.then
#944This was a bit tedious to do previously (see #944), and this PR simplifies this case a bit by making that calling
then
on aTask
returns aFuture
(which you can yield) instead of just aPromise
Approach & Alternate Designs
You can find some background in #944 and inline comments in this PR
TODOs and Open Questions
Future
s more easier in general? This has a chance of overlapping conceptually with thepipe
concept that was recently removed, and also overlaps with the idea ofcall
(althoughcall
returns anOperation
instead of aFuture
)then
returns aTask
instead of aFuture
? I tried this initially, but ran into some complications: Document equivalent toPromise.then
#944 (comment)