JavaScript中的迭代器和生成器是处理数据序列的重要特性,而异步迭代则是基于这些特性扩展出的处理异步数据流的能力,能够让我们用类似同步遍历的语法处理异步产生的数据。

迭代器与生成器基础回顾
迭代器
迭代器是一个对象,它定义了一个用于遍历数据集合的接口,核心是通过next()方法依次返回集合中的元素。一个标准的迭代器对象需要实现Symbol.iterator方法,该方法返回一个迭代器对象,迭代器对象的next()方法返回包含value和done两个属性的对象,value是当前元素值,done表示是否遍历完成。
下面是一个简单的自定义迭代器示例:
// 自定义一个简单的迭代器
const myIterator = {
data: [1, 2, 3],
index: 0,
[Symbol.iterator]() {
return this;
},
next() {
if (this.index < this.data.length) {
return { value: this.data[this.index++], done: false };
}
return { value: undefined, done: true };
}
};
// 使用for...of遍历迭代器
for (const item of myIterator) {
console.log(item); // 依次输出1、2、3
}
生成器
生成器是创建迭代器的更简洁方式,通过function*语法定义,函数内部使用yield关键字暂停函数执行并返回值,调用生成器函数会返回一个生成器对象,该对象本身就是一个迭代器。
生成器的基础使用示例:
// 定义生成器函数
function* numberGenerator() {
yield 1;
yield 2;
yield 3;
}
// 获取生成器对象(迭代器)
const gen = numberGenerator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
异步迭代的实现原理
同步迭代器只能处理同步产生的数据,当我们需要遍历异步产生的数据序列时,就需要用到异步迭代。异步迭代的核心是实现Symbol.asyncIterator方法,该方法返回一个异步迭代器对象,异步迭代器的next()方法返回一个Promise,该Promise resolve后得到包含value和done的对象。
异步迭代器的基本结构如下:
// 自定义异步迭代器
const asyncIterator = {
data: [1, 2, 3],
index: 0,
[Symbol.asyncIterator]() {
return this;
},
next() {
return new Promise((resolve) => {
// 模拟异步获取数据
setTimeout(() => {
if (this.index < this.data.length) {
resolve({ value: this.data[this.index++], done: false });
} else {
resolve({ value: undefined, done: true });
}
}, 1000);
});
}
};
异步生成器实现异步迭代
和同步生成器简化同步迭代器创建一样,异步生成器可以简化异步迭代器的创建,通过async function*语法定义异步生成器,函数内部可以使用await处理异步操作,使用yield返回异步得到的值。
异步生成器的使用示例:
// 定义异步生成器函数
async function* asyncNumberGenerator() {
// 模拟异步获取第一个值
await new Promise(resolve => setTimeout(resolve, 1000));
yield 1;
// 模拟异步获取第二个值
await new Promise(resolve => setTimeout(resolve, 1000));
yield 2;
// 模拟异步获取第三个值
await new Promise(resolve => setTimeout(resolve, 1000));
yield 3;
}
// 使用for await...of遍历异步迭代器
(async () => {
const gen = asyncNumberGenerator();
for await (const item of gen) {
console.log(item); // 每隔1秒依次输出1、2、3
}
})();
同步迭代与异步迭代的对比
两者的核心差异如下:
| 对比项 | 同步迭代 | 异步迭代 |
|---|---|---|
| 迭代器方法 | Symbol.iterator | Symbol.asyncIterator |
| next()返回值 | 直接返回{value, done} | 返回Promise,resolve后为{value, done} |
| 遍历语法 | for...of | for await...of |
| 适用场景 | 同步数据序列遍历 | 异步数据序列遍历(如异步接口分页数据、流数据等) |
异步迭代的常见使用场景
- 处理分页异步接口数据:逐页请求接口,用异步迭代依次处理每一页的数据,无需手动维护页码和请求逻辑。
- 读取流数据:比如读取文件流、网络请求流,流数据是分块异步到达的,用异步迭代可以逐块处理数据。
- 处理定时产生的异步任务结果:比如每隔一段时间执行一个异步任务,用异步迭代依次获取每个任务的结果。
注意事项
使用for await...of遍历时,必须在async函数内部使用,因为for await...of本身会处理异步迭代的Promise,需要在异步上下文中执行。
异步生成器中如果抛出错误,会被包装成rejected的Promise,需要在遍历时使用try...catch捕获错误,避免程序异常中断。
async function* errorGenerator() {
yield 1;
throw new Error('生成器执行出错');
yield 2;
}
(async () => {
try {
for await (const item of errorGenerator()) {
console.log(item); // 输出1
}
} catch (err) {
console.log(err.message); // 输出"生成器执行出错"
}
})();
JavaScript迭代器生成器异步迭代修改时间:2026-07-17 13:45:29