JavaScript 异步迭代器与 for await...of
异步迭代器用于遍历异步数据源,for await...of 是异步版本的 for...of,自动等待每个迭代值解析。
异步迭代器基础
JavaScript
// 同步迭代器:Symbol.iterator
const syncIterable = {
[Symbol.iterator]() {
let i = 0;
return {
next() {
if (i < 3) return { value: i++, done: false };
return { done: true };
}
};
}
};
// 异步迭代器:Symbol.asyncIterator
const asyncIterable = {
[Symbol.asyncIterator]() {
let i = 0;
return {
async next() { // async next 方法
if (i < 3) {
await new Promise(r => setTimeout(r, 100)); // 模拟异步
return { value: i++, done: false };
}
return { done: true };
}
};
}
};
for await...of 语法
JavaScript
// 必须在 async 函数中使用
async function consumeAsyncIterable() {
for await (const value of asyncIterable) {
console.log(value); // 0, 1, 2(自动等待)
}
}
consumeAsyncIterable();
// 等价于手动迭代
async function manualIterate() {
const iterator = asyncIterable[Symbol.asyncIterator]();
let result;
while (!(result = await iterator.next()).done) {
console.log(result.value);
}
}
异步生成器函数
JavaScript
// async generator:最简单的异步迭代器实现
async function* asyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
}
(async () => {
for await (const value of asyncGenerator()) {
console.log(value); // 1, 2, 3
}
})();
// 模拟流式数据
async function* fetchChunks(url) {
const response = await fetch(url);
const reader = response.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
yield value; // 逐块产出
}
}
// 处理分页数据
async function* fetchPages(baseUrl) {
let page = 1;
while (true) {
const response = await fetch(`${baseUrl}?page=${page}`);
const data = await response.json();
if (data.items.length === 0) break;
yield data.items;
page++;
}
}
(async () => {
for await (const items of fetchPages('/api/products')) {
console.log('收到数据:', items);
}
})();
异步迭代器返回方法
JavaScript
async function* generator() {
try {
yield 1;
yield 2;
yield 3;
} finally {
console.log('清理资源'); // return 时执行
}
}
(async () => {
const gen = generator();
console.log(await gen.next()); // { value: 1, done: false }
// 提前终止,触发 finally
await gen.return('手动终止');
console.log(await gen.next()); // { value: undefined, done: true }
})();
// throw 方法
(async () => {
const gen = generator();
await gen.next();
await gen.throw(new Error('迭代器错误')); // 抛出错误
})();
与同步迭代器对比
JavaScript
// 同步迭代器
const sync = {
[Symbol.iterator]() {
return {
next() {
return { value: 1, done: false }; // 直接返回值
}
};
}
};
for (const v of sync) {
console.log(v); // 立即输出
}
// 异步迭代器
const async = {
[Symbol.asyncIterator]() {
return {
async next() {
return { value: await Promise.resolve(1), done: false }; // 返回 Promise
}
};
}
};
// 需要 async 环境
(async () => {
for await (const v of async) {
console.log(v); // 等待后输出
}
})();
| 特性 | 同步迭代器 | 异步迭代器 |
|---|---|---|
| Symbol | Symbol.iterator | Symbol.asyncIterator |
| next() 返回 | { value, done } | Promise<{ value, done }> |
| 遍历语法 | for...of | for await...of |
| 迭代器方法 | 普通 next() | async next() |
实际应用场景
JavaScript
// 读取流数据
async function readStream(stream) {
const chunks = [];
for await (const chunk of stream) {
chunks.push(chunk);
}
return Buffer.concat(chunks);
}
// 处理事件序列(Node.js)
const { EventEmitter } = require('events');
async function* eventsToAsyncIterator(emitter, eventName) {
const queue = [];
const resolveQueue = [];
emitter.on(eventName, (data) => {
if (resolveQueue.length) {
resolveQueue.shift()(data);
} else {
queue.push(data);
}
});
while (true) {
if (queue.length) {
yield queue.shift();
} else {
yield await new Promise(resolve => resolveQueue.push(resolve));
}
}
}
// 批量异步处理
async function* batchProcess(items, batchSize) {
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
yield await Promise.all(batch.map(processItem));
}
}
(async () => {
for await (const results of batchProcess([1,2,3,4,5,6], 2)) {
console.log('批次结果:', results);
}
})();
注意事项
for await...of必须在 async 函数内使用- 异步迭代器不能用普通
for...of遍历- 异步生成器函数必须用
async function*定义- 提前终止会触发
finally块执行清理
JavaScript
// 错误:同步遍历异步迭代器
for (const v of asyncIterable) {
console.log(v); // TypeError: asyncIterable is not iterable
}
// 正确:异步遍历
(async () => {
for await (const v of asyncIterable) {
console.log(v);
}
})();
// 异步迭代器可以同步 next(),但返回 Promise
const iterator = asyncIterable[Symbol.asyncIterator]();
iterator.next(); // 返回 Promise,不是 { value, done }
要点总结
- 异步迭代器使用
Symbol.asyncIterator定义,next()返回 Promise for await...of自动等待每个迭代值,必须在 async 函数内使用- 异步生成器
async function*是最简洁的异步迭代器实现 - 异步迭代器支持
return()和throw()方法 - 适用于流数据处理、分页数据、事件序列等异步数据源
- 提前终止触发
finally,适合资源清理场景
📝 发现内容有误?点击此处直接编辑