极简三分钟ES6 - ES9中for await of

快递站取快递

想象你同时网购了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,用同步语法遍历异步集合,数据随到随处理,不积压内存,随时中断/恢复迭代

相关推荐
吃糖的小孩29 分钟前
从只读页面到可控真实探针:我如何给 Owner Console 加手动诊断
前端
谷无姜29 分钟前
为什么你的性能优化无效?可能是"木桶效应"在作祟
前端·性能优化
雾非雾33 分钟前
《基于具身交互智能数字人技术:如何打造AI数字人宣讲平台"红厅智播”》
前端
Revolution6142 分钟前
一段 JavaScript 代码执行时,到底发生了什么
前端·javascript
智能起源43 分钟前
关于元素层级过多,导致压祯的问题(使用winform或者WPF应用的webview组件嵌套网页时,动效卡顿问题)
前端
Old Uncle Tom1 小时前
银行用户画像 -- 金融目标与需求意图
前端·人工智能·金融
IT_陈寒2 小时前
Vue的响应式让我加班到凌晨3点,原来问题出在这
前端·人工智能·后端
东方小月2 小时前
从0开发一个 Coding Agent(一):前言
前端·人工智能·typescript
恋猫de小郭2 小时前
Flutter 全新真 3D 实现,用 flutter_scene 能开发一个「我的世界」
android·前端·flutter