Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Migrating from Generators to Async/Await

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.

like image 560
Glstunna Avatar asked Jan 10 '17 22:01

Glstunna


People also ask

Does async await use generators?

Async/await makes it easier to implement a particular use case of Generators. The return value of the generator is always {value: X, done: Boolean} whereas for async functions, it will always be a promise that will either resolve to the value X or throw an error.

Is async await better than promises?

Async/Await is used to work with promises in asynchronous functions. It is basically syntactic sugar for promises. It is just a wrapper to restyle code and make promises easier to read and use. It makes asynchronous code look more like synchronous/procedural code, which is easier to understand.

Can we replace promise with async await?

Promises and async/await are interchangeable. Whenever you see an await -statement, you can replace it with a . then() .

How is async await implemented?

JavaScript Async FunctionsAsync and await are built on promises. The keyword “async” accompanies the function, indicating that it returns a promise. Within this function, the await keyword is applied to the promise being returned. The await keyword ensures that the function waits for the promise to resolve.


2 Answers

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 …().

like image 79
Bergi Avatar answered Sep 17 '22 06:09

Bergi


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([...]);
like image 26
Estus Flask Avatar answered Sep 17 '22 06:09

Estus Flask