ES6: how to split an async generator function without losing yield ability

Viewed 283

I have an async generator function (of a batch job), which got quite big over time. I want to split it into multiple functions :

async *execute(): AsyncGenerator<ISyncState> {

   await doThis();
   await doThis2();
   await doThis3();
   yield "this";

   await doThis4();
   await doThis5();
   await doThat();
   yield "that";

   // .. many more functions

}

async doThis() {...}
async doThat() {...}
async doThis2() {...}

Caller :

const gen = execute();
for await (const syncState of gen)
    // do something

I want to turn it into :

async *execute(): AsyncGenerator<ISyncState> {

   await step1();

   await step2();

   await step3();
}

async step1() {
   await doThis();
   yield "this1"; <-- doesn't work
   await doThis2();
   yield "this2"; <-- doesn't work
   await doThis3();
   yield "this3"; <-- doesn't work
}

Is there a way to yield from within "step1()"? (what would be the best way to solve this?)

2 Answers

Just like in a normal generator, you can use yield* inside an async generator to yield that a sub-generator yields, even if the sub-generator is async too:

const doThis = () => Promise.resolve();

async function* execute() {

   yield* step1();

   // await step2();

   // await step3();
}

async function* step1() {
   await doThis();
   // await doThis2();
   // await doThis3();
   yield "this";
}

(async () => {
  for await (const item of execute()) {
    console.log(item);
  }
})();

You make your "steps" themselves async generators. Something like this:

async function *step1() {
  yield await step1a();
  yield await step1b();
  yield await step1c();
}

Then you can say something like this, using for await...of:

async function *execute() {

  for await ( item of step1() ) {
    yield item;
  }

  for await ( item of step2() ) {
    yield item;
  }

  for await ( item of step3() ) {
    yield item;
  }

  . . .

}
Related