It is tempting to keep these transformations independent, so that
async function f(a, b) {
var c = g(a, b);
return await h(c);
}
becomes
function f(a, b) {
return spawn(function*() {
var c = g(a, b);
return yield h(c)
});
}
and then Regenerator can transform generator functions and yield expressions:
function f(a, b) {
return spawn(wrapGenerator.mark(function() {
var c;
return wrapGenerator(function($ctx2) {
while (1) switch ($ctx2.prev = $ctx2.next) {
case 0:
c = g(a, b);
$ctx2.next = 3;
return h(c);
case 3:
return $ctx2.abrupt("return", $ctx2.sent);
case 4:
case "end":
return $ctx2.stop();
}
}, this);
}));
}
However, this approach misses a significant optimization opportunity, given that spawn immediately invokes the generator function!
Instead, we would ideally like to generate the following code:
function f(a, b) {
var c;
return spawnIter(wrapGenerator(function($ctx2) {
while (1) switch ($ctx2.prev = $ctx2.next) {
case 0:
c = g(a, b);
$ctx2.next = 3;
return h(c);
case 3:
return $ctx2.abrupt("return", $ctx2.sent);
case 4:
case "end":
return $ctx2.stop();
}
}, this));
}
where spawnIter is a version of the spawn function that takes an iterable object and does not try to invoke it as if it were a GeneratorFunction.