effection
effection copied to clipboard
Allow yielding a chain of `then` on `Task`
Motivation
There are cases where you need to do the following steps:
- Create a
Task(usingrun) - Do some computation on the
Taskusingthen yieldthe result of the task
example that shows how this can be used to:
- implement #946 without requiring to use
async/awaitexplicitly anywhere - easily chain things without having to awkwardly wrap results with
callas in #944
class Foo {
task: Future<number>;
constructor() {
this.task = run(() => ...).then(val => val+1);
}
*doWork() {
yield* this.task;
}
}
This was a bit tedious to do previously (see #944), and this PR simplifies this case a bit by making that calling then on a Task returns a Future (which you can yield) instead of just a Promise
Approach & Alternate Designs
You can find some background in #944 and inline comments in this PR
TODOs and Open Questions
- [ ] Do we want to make creating
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) - [ ] Is there a way to make that
thenreturns aTaskinstead of aFuture? I tried this initially, but ran into some complications: https://github.com/thefrontside/effection/issues/944#issuecomment-2564596508
I'm wondering about the corner cases here.
- Will the returned promises be lazy? I.e.
- What if the return value is an operation vs a promise vs a regular value?
I.e. what would be the expectation around this:
run(fn).then(function*(value) { return value + 1 })
- The laziness is not changed by this PR. Nothing happens (lazy) until you use
awaitjust like before this PR - Currently, the behavior is the same as promises in generally. That is to say,
- if you return a value, it stays a value
- if you return a promise, it gets flattened to a value (
.then(() => Promise.resolve(3))becomes just3) - If you return a generator, it doesn't get flattened (it gets treated as case 1 and just returns a generator)
You could say that may we would like then to flatten generators as well for usability reasons, but this is not possible because the type definition of then comes from Promise (we cannot just arbitrarily change it). You could introduce a new function in the Future interface that flattens both promises in generators if we want