async generator function
Basic Concepts of ECMAScript 6 Async Generator Functions
Async generator functions combine the features of async functions and generator functions in ES6, allowing developers to write asynchronous code in a synchronous style. These functions are declared using the async function*
syntax and can use the yield
keyword to pause execution while also handling asynchronous operations with await
.
async function* asyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
}
Syntax Structure of Async Generator Functions
The syntax of async generator functions is similar to that of regular generator functions, but with the async
modifier added before the function
keyword:
async function* name([param[, param[, ...param]]]) {
// Function body
}
This type of function returns an async generator object, which implements both the async iteration protocol and the iterator protocol. Each call to the next()
method returns a Promise that resolves to an object with value
and done
properties.
How Async Generator Functions Work
When an async generator function is called, it does not immediately execute the function body. Instead, it returns an async generator object. The function body only begins execution when the next()
method of this object is called, and it runs until the first yield
expression is encountered:
async function* fetchInSequence(urls) {
for (const url of urls) {
const response = await fetch(url);
yield response.json();
}
}
const generator = fetchInSequence(['url1', 'url2', 'url3']);
generator.next().then(result => console.log(result));
Using for await...of
Loops with Async Generators
The for await...of
loop is a syntax specifically designed for asynchronous iteration, making it easy to traverse values produced by async generators:
async function* generateSequence(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
(async () => {
for await (const value of generateSequence(1, 5)) {
console.log(value); // 1, 2, 3, 4, 5 (outputs one every 100ms)
}
})();
Error Handling in Async Generator Functions
Errors in async generator functions can be caught using try-catch blocks or handled via the catch
method of the returned Promise:
async function* asyncGeneratorWithError() {
try {
yield await Promise.resolve('Success');
throw new Error('Something went wrong');
} catch (error) {
yield `Caught error: ${error.message}`;
}
}
const generator = asyncGeneratorWithError();
generator.next().then(console.log); // { value: 'Success', done: false }
generator.next().then(console.log); // { value: 'Caught error: Something went wrong', done: false }
Practical Use Cases for Async Generator Functions
- Paginated Data Loading: Implementing lazy-loading data streams
async function* paginatedFetcher(endpoint) {
let page = 1;
while (true) {
const response = await fetch(`${endpoint}?page=${page}`);
const data = await response.json();
if (data.length === 0) return;
yield data;
page++;
}
}
- WebSocket Message Processing: Handling real-time data streams
async function* webSocketListener(url) {
const socket = new WebSocket(url);
try {
while (true) {
const message = await new Promise(resolve => {
socket.addEventListener('message', resolve, { once: true });
});
yield message.data;
}
} finally {
socket.close();
}
}
Differences Between Async Generator Functions and Regular Generator Functions
Feature | Async Generator Functions | Regular Generator Functions |
---|---|---|
Declaration | async function* |
function* |
Return Value | Async generator object | Generator object |
next() Return Value |
Promise | Plain object |
Iterable Protocol | Async iterator | Sync iterator |
Internal Usage | await and yield |
Only yield |
Combining Async Generator Functions
Async generator functions can be combined with other asynchronous operations to create complex data processing pipelines:
async function* mapAsync(asyncIterable, mapper) {
for await (const item of asyncIterable) {
yield await mapper(item);
}
}
async function* filterAsync(asyncIterable, predicate) {
for await (const item of asyncIterable) {
if (await predicate(item)) {
yield item;
}
}
}
(async () => {
const numbers = generateSequence(1, 10);
const squared = mapAsync(numbers, async n => n * n);
const evenSquares = filterAsync(squared, async n => n % 2 === 0);
for await (const num of evenSquares) {
console.log(num); // 4, 16, 36, 64, 100
}
})();
Performance Considerations for Async Generator Functions
When using async generator functions, keep in mind:
- Each
yield
creates a new Promise object - Asynchronous operations introduce additional microtask queue overhead
- Memory usage may be higher than synchronous implementations
// Inefficient implementation
async function* inefficient() {
for (let i = 0; i < 1e6; i++) {
yield await Promise.resolve(i); // Creates a million Promises
}
}
// Improved implementation
async function* efficient() {
let buffer = [];
for (let i = 0; i < 1e6; i++) {
buffer.push(i);
if (buffer.length >= 1000) {
yield buffer;
buffer = [];
}
}
if (buffer.length > 0) yield buffer;
}
Advanced Patterns for Async Generator Functions
- Two-Way Communication: Passing values to the generator via
next()
async function* twoWayCommunication() {
const question1 = yield 'What is your name?';
console.log(question1); // User input
const question2 = yield `Hello ${question1}, how old are you?`;
console.log(question2); // User input
}
async function run() {
const generator = twoWayCommunication();
let result = await generator.next();
console.log(result.value); // "What is your name?"
result = await generator.next('Alice');
console.log(result.value); // "Hello Alice, how old are you?"
await generator.next(30);
}
run();
- Timeout Control: Implementing an async generator with timeout
async function* withTimeout(asyncIterable, timeout) {
for await (const item of asyncIterable) {
yield await Promise.race([
item,
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
]);
}
}
Async Generator Functions in Node.js
In Node.js, async generator functions are particularly well-suited for handling stream data:
const fs = require('fs');
const readline = require('readline');
async function* readLines(filePath) {
const fileStream = fs.createReadStream(filePath);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
try {
for await (const line of rl) {
yield line;
}
} finally {
rl.close();
fileStream.close();
}
}
(async () => {
for await (const line of readLines('large-file.txt')) {
console.log(line);
}
})();
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:async函数返回值
下一篇:top-level await