Consider:
async function* f() {
const x = Promise.resolve(1);
const y = Promise.resolve(2);
const fromX = yield x;
return y;
}
const g = f();
const a = Promise.resolve("a");
const b = Promise.resolve("b");
At this point we are suspended at the yield x
. Now let's feed a value into the generator:
const result1 = g.next(a);
We require:
result1
must be{ value: 1, done: false }
, because we've decided thatyield
<->yield await
.fromX === a
; we do not unwrap values passed in as arguments tonext()
, as they are not treated specially.
Now let's do it again:
const result2 = g.next(b);
We require:
result2
must be{ value: 2, done: false }
, because we wantreturn
<->return await
; this was not stated explicitly, but makes sense.b
is ignored, similar to the result of the last call to.next()
on a async generator.
Now let's try something different. Instead of .next()
, let's call .return()
:
const result1 = g.return(a);
The rough meaning of g.return(a)
is to turn the current yield
statement we're paused on into a return a
statement. If we take that literally, this implies we want to require:
result1
must be{ value: "a", done: true }
This is markedly different from how we behave for g.next(a)
, where we treated the parameter as opaque. But it falls out of the rough meaning of g.return(a)
.