8

I just came to the painful realization that generator functions cannot be used with await. Only promises or async functions.

My team built an entire application with all modules consisting of generator functions, with one call to the Co module from the main js file.

Besides going though hundreds of generator function and changing them from function*(...){ to async function(...){, how else can generators be made to work with async/await?

Makes no sense because yield*/generators and async/await are pretty similar in how they handle flow so I'm wondering how they missed out on having await support generators.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
Glstunna
  • 1,993
  • 3
  • 18
  • 27
  • 1
    FYI, `async/await` is not part of ES7. – Felix Kling Jan 10 '17 at 22:09
  • 1
    Also, if you want to rewrite large parts of your code base, consider using a tool to do it, if possible: https://github.com/facebook/jscodeshift (disclaimer: I wrote it) – Felix Kling Jan 10 '17 at 22:11
  • What's the reason for migration? – Bryan Chen Jan 10 '17 at 22:11
  • _"I just came to the painful realization that generator functions cannot be used with await. Only promises or async functions."_ Have not tried `async/await` though curious about patterns where generators were used which caused issues. Can you include an example of a generator function not being able to be used with `async/await` at Question? – guest271314 Jan 10 '17 at 22:14
  • "*Makes no sense because yield*/generators and async/await are pretty similar in how they handle flow*" - I don't get what you mean. They might be similar, but that does not mean they could be combined into something that is both. – Bergi Jan 10 '17 at 22:25
  • @Bergi - It actually Makes total sense. If a promise and an async function are awaitable, then why not a generator? In generator-land, both promises and generators are yieldable. – Glstunna May 07 '17 at 09:48
  • @Glstunna Because generators were not made for asynchrony. *Only* in `co` and other solutions that hack async/await semantics into generator functions, promises will be treated specially when yielded. – Bergi May 07 '17 at 12:14

3 Answers3

6

You have to go through your code base and change it, yes (of course you might write/use a tool that does everything for you).

But you can do it gradually if you want: Replace a function* by async function, inside it every yield by await and every yield* by await co(…), and then change every call to the former generator function from co(…) to …().

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
4

There's no urge to migrate from one to another because async functions and co library can coexist in peace.

async functions can be used inside co generator functions, they are just promise-returning functions:

co.wrap(function* () {
    yield asyncFn(1);
})()
.catch(console.error);

Generator functions can be used inside async functions:

(async function () {
    await co(genFn(1));
    // for generator functions with no arguments, can also be 
    await co(genFn);
})()
.catch(console.error);

Besides going though hundreds of generator function and changing them from function*(...){ to async function(...){, how else can generators be made to work with async/await?

Considering that the generators are used in the app only in conjunction with co, they can be replaced in automatic manner. function* and * methods are replaced with async counterparts, yield and yield* are replaced with await.

Before this can be done, some preliminary refactoring should be made. Only promises and generators should be used from this list of yieldables. Parallel execution (arrays and objects) should be replaced with respective Promise.all:

const results = yield [...];

to

const results = yield Promise.all([...]);
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
1

In case some one needs more information regarding migrating from co to async function, here is a detailed article about migration: https://medium.com/@nivekz/migrate-from-co-to-async-functions-4635d32d12bf

user716468
  • 1,513
  • 2
  • 13
  • 20