快递站取快递
想象你同时网购了3件商品(对应3个异步任务)
- 普通
for...of
:必须按顺序取快递(等第一个到了才能取第二个) for await...of
:快递站到货通知你(哪个先到先取哪个)
js
// 模拟三个快递请求
const fetchPackages = [
fetch('//快递1').then(r => r.json()),
fetch('//快递2').then(r => r.json()),
fetch('//快递3').then(r => r.json())
];
// 使用for await...of取快递
async function getDeliveries() {
for await (const pkg of fetchPackages) {
console.log(` 收到包裹:${pkg.name}`);
}
}
特性详解
能遍历异步迭代器(Async Iterable)
- 普通数组/Set/Map → 直接遍历
- 异步数据源(如网络流/数据库查询)→ 等待每个值完成再继续
js
// 创建异步迭代器(每秒生成一个随机数)
const asyncRandom = {
[Symbol.asyncIterator]: async function*() {
while(true) {
await new Promise(resolve => setTimeout(resolve, 1000));
yield Math.random();
}
}
};
// 遍历异步迭代器
(async () => {
for await (const num of asyncRandom) {
if(num > 0.9) break;
console.log(` 当前数值:${num}`);
}
})();
与同步迭代器的区别
特性 | for...of |
for await...of |
---|---|---|
迭代器类型 | 同步迭代器 | 异步迭代器 |
等待机制 | 同步执行 | 每个值都等待完成 |
适用数据源 | Array/Set/Map等 | 流/WebSocket/数据库 |
错误处理:try/catch
包裹
js
async function readStream() {
try {
for await (const chunk of networkStream) {
process(chunk);
}
} catch (err) {
console.error(" 数据流中断:", err);
}
}
一些常见的使用场景
分页API的连续请求
js
async function getAllPages() {
const pageRequests = [
fetch('//api?page=1'),
fetch('//api?page=2'),
fetch('//api?page=3')
];
// 哪个接口先响应先处理哪个
for await (const response of pageRequests) {
const data = await response.json();
render(data);
}
}
读取大文件流
js
import { createReadStream } from 'fs';
async function readBigFile() {
const stream = createReadStream('data.log');
for await (const chunk of stream) {
console.log(` 收到${chunk.length} 字节数据`);
}
}
WebSocket消息处理
js
const socket = new WebSocket('wss://实时数据');
async function handleMessages() {
for await (const msg of socket) { // 需实现异步迭代器
if (msg.type === 'ALERT') notifyUser(msg);
}
}
数据库批量查询
js
async function exportUserData() {
const query = db.query('SELECT * FROM users');
for await (const user of query) {
writeToCSV(user); // 逐条写入CSV
}
}
并发任务状态监控
js
const tasks = [
backupDatabase(), // 返回Promise
uploadLogs(),
sendEmails()
];
async function monitorTasks() {
for await (const result of tasks) {
updateProgressBar(result.taskId);
}
}
一些特殊场景
同步与异步混合遍历
js
const mixedSources = [
Promise.resolve(' 异步苹果'),
'同步香蕉',
Promise.resolve(' 异步橙子')
];
for await (const item of mixedSources) {
console.log(item); // 正常输出所有值
}
提前终止迭代
js
// 通过break/return/throw终止
for await (const data of sensorStream) {
if (data.temperature > 100) {
shutdownSystem();
break; // 停止监听
}
}
与生成器结合
js
async function* genAsyncData() {
yield await fetch('//data1');
yield await fetch('//data2');
}
for await (const data of genAsyncData()) {
// 处理数据
}
与传统方案对比
需求 | Promise.all() 方案 |
for await...of 方案 |
优势 |
---|---|---|---|
按序处理异步任务 | ❌(必须全部完成) | ✅(顺序处理) | 节省内存,即时处理 |
处理无限数据流 | 不可能实现 | ✅ | 唯一解决方案 |
错误处理 | 单个失败导致全部失败 | ✅(可单独捕获) | 容错性强 |
动态添加任务 | ❌ | ✅(可配合数组追加) | 灵活扩展 |
牢记
for await...of
= 异步世界的for...of
,用同步语法遍历异步集合,数据随到随处理,不积压内存,随时中断/恢复迭代