异步迭代器核心是将持续到达的数据块转为for await...of可消费的异步序列,兼顾内存友好与逻辑清晰;支持原生流、自定义封装、背压控制及兼容性检查。

异步迭代器处理流式数据的核心,是把“持续到达的数据块”变成可被 for await...of 逐个消费的异步序列,既保持内存友好,又让逻辑清晰可控。
直接用 for await...of 消费原生流
Node.js 的 ReadableStream 和浏览器的 Response.body(配合 getReader())都实现了 Symbol.asyncIterator,天然支持异步迭代:
- 读取大文件时,无需一次性加载进内存:
const stream = fs.createReadStream('huge.log');for await (const chunk of stream) {console.log('收到数据块:', chunk.length);} - 处理 fetch 返回的 SSE 或普通响应流:
const res = await fetch('/api/stream');const reader = res.body.getReader();while (true) {const { done, value } = await reader.read();if (done) break;console.log(new TextDecoder().decode(value));}
用异步生成器封装自定义流逻辑
当原始数据源不直接支持异步迭代(比如分页 API、WebSocket 消息、轮询接口),就用 async function* 把获取逻辑封装成异步可迭代对象:
- 分页拉取:每 yield 一页数据,调用方按需遍历,中途可
break;async function* fetchPages(url) {let page = 1;while (true) {const res = await fetch(`${url}?page=${page}`);const data = await res.json();if (!data.length) return;yield* data;page++;}} - WebSocket 封装:把事件监听转为异步迭代,避免手动管理
onmessage:async function* wsMessages(ws) {return new Promise((resolve, reject) => {ws.onmessage = e => resolve(e.data);ws.onerror = reject;});// 实际中需配合事件循环或更健壮的包装
结合背压控制写入目标流
流式复制(如文件拷贝、代理转发)必须考虑写入端是否能跟上读取速度。异步迭代天然配合背压:
立即学习“Java免费学习笔记(深入)”;
- 每次
await writable.write(chunk)后,如果返回false,说明缓冲区已满,for await会自动暂停,直到'drain'事件触发; - 无需手动监听事件或维护队列,整个流程由迭代器驱动,代码简洁且安全:
async function copyStream(readable, writable) {writable.on('error', err => {/* 处理错误 */});for await (const chunk of readable) {await new Promise(resolve => {if (writable.write(chunk)) resolve();else writable.once('drain', resolve);});}}
注意边界与兼容性
使用前确认几个关键点:
-
for await...of必须在async函数内使用,不能出现在顶层或普通函数中; - 目标对象必须实现
[Symbol.asyncIterator](),返回一个next()方法,且该方法返回Promise<{ value, done }>; - 浏览器中部分旧版本(如 IE)不支持,Node.js 需 v10.0+,生产环境建议检查运行时能力;
- 若要对 Promise 数组做“逐个等待”,需先用异步生成器包装:
async function* fromPromises(arr) { for (const p of arr) yield await p; }


















