I'm having a generator that, among other operations, queries a database, like
function* current(db) {
const items = await db.collection('...').find({ ... });
for (const item of items)
if (...) yield item;
}
which isn't valid syntax. Using promises and yielding from a then
, isn't possible either.
What should I do then? How can I use asynchronous operation inside a generator?
Among those features are generator functions and async/await. Generator functions give you the ability to pause and continue the execution of a program. In contrast, async/await gives you the ability to write asynchronous code without falling into "callback hell", which you risk when writing standard promises.
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.
You need to place the loop in an async function, then you can use await and the loop stops the iteration until the promise we're awaiting resolves. You could also use while or do.. while or for loops too with this same structure.
The await operator is used to wait for a Promise . It can only be used inside an async function within regular JavaScript code; however it can be used on its own with JavaScript modules.
A generator function is executed yield by yield i.e one yield-expression at a time by its iterator (the next method) whereas async-await, they are executed sequential await by await. Async/await makes it easier to implement a particular use case of Generators .
A generator function is executed yield by yield i.e one yield-expression at a time by its iterator (the next method) whereas a sync-await, they are executed sequential await by await. Async/await makes it easier to implement a particular use case of Generators.
For a function to use async/await, it only needs to be declared as async. Here's an example of the fetchUsers function rewritten into a strictly async function (no generator): You can still make this function a generator and pause the function whenever you'd like:
When a generator function is called, its body is not executed right away. Instead it returns an iterator-object which adheres to the iterator protocol i.e. it has a next method. The only way to execute the body of gen is by calling the next method on its iterator-object.
Calling await
in generators (aka async generators) has been supported natively in Node v10+ (released April 2018) and Chrome since v63, as well as Firefox v57.
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getAsyncData() {
await sleep(1000); // simulate database/network delay...
return [1, 2, 3, 4, 5]; // ...then return some data
}
// async generator
async function* filterAsyncData() {
const items = await getAsyncData(); // await call in generator
for (const item of items)
if (item % 2) yield item;
}
(async function main() {
// for-await syntax
for await (const filteredItem of filterAsyncData())
console.log(filteredItem);
// classic iterator syntax
const fadIt = filterAsyncData();
while (true) {
const result = await fadIt.next(); // note await
if (result.done) break;
console.log(result.value);
}
}());
Compared to a regular (non-async) generators, remember to use await
before calling .next()
. Alternatively, the new for-await-of
syntax has been available since Node v9.2, and can be used in Node v10 without any flags.
For older versions of node (or for Jest), you can use the Babel plugin transform-async-generator-functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With