在JavaScript的异步编程场景中,异步迭代是一种处理连续异步数据的重要方式,而for await of语法就是专门用于遍历异步可迭代对象的循环结构,它能让异步数据的遍历逻辑更接近同步代码的书写习惯。

for await of的基本语法
for await of的语法结构和普通的for of循环类似,不过需要放在async函数内部使用,基本格式如下:
async function iterateAsyncData() {
for await (const item of asyncIterable) {
// 处理每个异步获取到的item
console.log(item);
}
}
这里的关键要求是遍历的目标必须是异步可迭代对象,也就是对象需要实现Symbol.asyncIterator方法,该方法返回一个异步迭代器,每次调用迭代器的next方法都会返回一个Promise,resolve后得到下一个数据项。
异步可迭代对象的实现方式
异步生成器函数
最常用的创建异步可迭代对象的方式是使用异步生成器函数,函数内部用yield返回每个异步获取到的值,示例如下:
// 定义一个异步生成器,每隔1秒生成一个数字
async function* asyncNumberGenerator() {
let num = 1;
while (num <= 3) {
// 模拟异步操作,比如接口请求、文件读取等
await new Promise(resolve => setTimeout(resolve, 1000));
yield num;
num++;
}
}
// 使用for await of遍历
async function run() {
for await (const num of asyncNumberGenerator()) {
console.log(num); // 每隔1秒依次输出1、2、3
}
console.log('遍历完成');
}
run();
自定义异步可迭代对象
也可以手动实现Symbol.asyncIterator方法来创建异步可迭代对象,示例如下:
const asyncIterableObj = {
data: [10, 20, 30],
index: 0,
[Symbol.asyncIterator]() {
return {
next: async () => {
if (this.index < this.data.length) {
// 模拟异步获取数据
await new Promise(resolve => setTimeout(resolve, 500));
return { value: this.data[this.index++], done: false };
}
return { value: undefined, done: true };
}
};
}
};
async function handleObj() {
for await (const val of asyncIterableObj) {
console.log(val); // 每隔500ms依次输出10、20、30
}
}
handleObj();
for await of与普通for of的核心区别
| 对比维度 | 普通for of | for await of |
|---|---|---|
| 适用对象 | 同步可迭代对象(实现Symbol.iterator) | 异步可迭代对象(实现Symbol.asyncIterator) |
| 使用环境 | 可放在普通函数或async函数中使用 | 只能放在async函数内部使用 |
| 迭代器next返回值 | 直接返回{value, done}对象 | 返回Promise,resolve后得到{value, done}对象 |
| 处理异步数据 | 无法直接处理,需要额外写await逻辑 | 自动等待每个异步迭代项完成再进入下一次循环 |
实际应用场景
处理分页异步接口数据
当需要连续请求多页数据,且后一页请求依赖前一页的返回结果时,使用for await of可以简化逻辑:
// 模拟分页请求接口
async function* fetchPageData() {
let page = 1;
let hasMore = true;
while (hasMore) {
// 模拟接口请求,返回当前页数据和是否有更多页的标识
const res = await mockApiRequest(page);
yield res.data;
hasMore = res.hasMore;
page++;
}
}
// 模拟接口请求函数
function mockApiRequest(page) {
return new Promise(resolve => {
setTimeout(() => {
if (page <= 3) {
resolve({
data: [`第${page}页数据1`, `第${page}页数据2`],
hasMore: true
});
} else {
resolve({ data: [], hasMore: false });
}
}, 1000);
});
}
async function loadAllData() {
for await (const pageData of fetchPageData()) {
console.log('当前页数据:', pageData);
// 处理当前页数据
}
console.log('所有数据加载完成');
}
loadAllData();
读取异步数据流
在处理Node.js中的可读流这类异步数据流时,也可以配合for await of使用,示例如下:
// Node.js环境下读取文件流的示例
const fs = require('fs');
async function readFileStream() {
const readableStream = fs.createReadStream('./test.txt', { encoding: 'utf8' });
for await (const chunk of readableStream) {
console.log('读取到数据块:', chunk);
}
console.log('文件读取完成');
}
readFileStream();
使用注意事项
- for await of必须放在async函数内部,否则会抛出语法错误。
- 如果遍历的异步可迭代对象中途抛出错误,循环会终止,错误需要开发者自行在try catch中捕获处理。
- 不要对非异步可迭代对象使用for await of,比如普通的数组,虽然不会报错,但完全没有必要,反而会增加不必要的异步开销。
- 异步迭代的过程中,下一次迭代会等待上一次迭代的Promise完成之后才会执行,所以如果是需要并发处理的异步任务,不适合用for await of,应该用Promise.all配合普通循环。
异步迭代和for await of是JavaScript处理连续异步数据的高效语法,合理运用可以减少回调嵌套,让异步数据遍历的代码更清晰易读,开发者可以根据实际的业务场景选择合适的用法。
for_await_of异步迭代JavaScriptasync_generator修改时间:2026-06-15 08:36:33