JavaScript中的异步生成器与异步迭代
字数 694 2025-11-22 11:40:18
JavaScript中的异步生成器与异步迭代
描述
异步生成器是ES2018引入的特性,它结合了生成器函数和异步函数的特点,允许你使用生成器语法来生成一系列异步产生的值。与异步迭代器协议配合使用,可以优雅地处理异步数据流,比如分页API、实时数据流等场景。
核心概念解析
- 异步生成器函数:使用
async function*声明的函数,内部可以使用yield来产生值 - 异步迭代器:实现了
[Symbol.asyncIterator]方法的对象 - 异步迭代:使用
for await...of循环来消费异步生成的值
异步生成器函数的基本结构
async function* asyncGenerator() {
yield await Promise.resolve(1); // 产生异步值1
yield await Promise.resolve(2); // 产生异步值2
yield await Promise.resolve(3); // 产生异步值3
}
异步迭代的工作原理
- 调用异步生成器函数返回一个异步迭代器对象
- 异步迭代器的
next()方法返回一个Promise - 每个Promise解析后包含
{value, done}对象
手动消费异步生成器
const asyncIter = asyncGenerator();
// 手动调用next()消费
asyncIter.next().then(result => {
console.log(result); // {value: 1, done: false}
return asyncIter.next();
}).then(result => {
console.log(result); // {value: 2, done: false}
return asyncIter.next();
}).then(result => {
console.log(result); // {value: 3, done: false}
return asyncIter.next();
}).then(result => {
console.log(result); // {value: undefined, done: true}
});
使用for await...of简化消费
async function consumeAsyncGenerator() {
for await (const value of asyncGenerator()) {
console.log(value); // 依次输出: 1, 2, 3
}
}
实际应用示例:分页数据获取
async function* paginatedFetcher(url) {
let currentPage = 1;
let hasMore = true;
while (hasMore) {
// 模拟异步API调用
const response = await fetch(`${url}?page=${currentPage}`);
const data = await response.json();
yield data.items; // 产生当前页的数据
hasMore = data.hasMore;
currentPage++;
}
}
// 使用示例
async function processAllPages() {
for await (const pageData of paginatedFetcher('/api/data')) {
console.log('Processing page:', pageData);
// 处理每一页的数据
}
}
错误处理机制
async function* asyncGeneratorWithError() {
try {
yield await Promise.resolve(1);
throw new Error('Something went wrong');
yield await Promise.resolve(2); // 不会执行
} catch (error) {
yield `Error handled: ${error.message}`;
}
}
// 消费时的错误处理
async function handleErrors() {
try {
for await (const value of asyncGeneratorWithError()) {
console.log(value); // 1, "Error handled: Something went wrong"
}
} catch (error) {
console.error('Outer error:', error);
}
}
与普通生成器的关键区别
- 异步生成器的
next()返回Promise,普通生成器返回普通对象 - 使用
for await...of而不是for...of - 可以在
yield后面跟Promise或异步操作
实现自定义异步可迭代对象
class AsyncRange {
constructor(start, end) {
this.start = start;
this.end = end;
}
async *[Symbol.asyncIterator]() {
for (let i = this.start; i <= this.end; i++) {
// 模拟异步延迟
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
}
// 使用自定义异步可迭代对象
async function demo() {
const asyncRange = new AsyncRange(1, 5);
for await (const num of asyncRange) {
console.log(num); // 每隔100ms输出一个数字
}
}
性能考虑和最佳实践
- 使用
break或return提前终止循环可以避免不必要的异步计算 - 注意错误传播机制,异步生成器内部的错误会通过Promise rejection传播
- 考虑使用
try...finally进行资源清理
异步生成器为处理异步数据流提供了声明式的语法糖,让异步代码的编写更加直观和易于维护。