Async Iterator 可自然实现分块流式读取并优雅错误处理:每次 next() 返回 Promise,解析为 {value, done} 或拒绝;for await...of 自动抛出拒绝错误;用 async function* 定义,yield 逐块产出,支持异步拉取与自动终止。

JavaScript 中的 Async Iterator 可以自然实现分块流式读取,同时配合 try...catch 和迭代器协议本身的 throw() 方法,能优雅处理读取过程中的错误。关键在于:让异步迭代器每次 next() 返回一个 Promise,该 Promise 解析为 { value, done },并在出错时被拒绝;而消费端用 for await...of 时,内部会自动处理 Promise 拒绝并抛出,便于集中捕获。
分块流式读取的核心实现
以读取大型文件(如通过 ReadableStream)或分页 API 为例,异步迭代器应按需拉取下一块数据,而不是一次性加载全部:
- 定义一个返回
AsyncIterator的函数(通常用async function*语法最简洁) - 在函数体内用
yield逐次产出每个数据块(yield后的表达式会被自动包装为 Promise) - 每轮
yield前可做异步操作,如fetch下一页、stream.read()一段、或await readFileChunk() - 当无更多数据时,不
yield并让函数自然结束,迭代器自动返回{ value: undefined, done: true }
示例:模拟分页 API 的异步迭代器
for await...of
- 正常情况下,每次循环体执行前,自动等待上一个
yield的 Promise 完成 - 如果某次
next()返回的 Promise 被拒绝(例如 fetch 失败),for await会立即退出循环,并将错误抛出到外层作用域 - 因此只需在外层加
try...catch即可捕获整个流过程中的任意错误
示例:
async function processPages() {
try {
for await (const page of fetchPages('https://api.example.com/items')) {
console.log('Processing', page.length, 'items');
await saveToDB(page); // 可能也失败,但属于业务逻辑,不影响迭代器本身
}
console.log('All pages processed');
} catch (err) {
console.error('Stream interrupted:', err.message);
// 可在此触发重试、降级、上报等
}
}
手动调用 next() 时的错误处理细节
若不用 for await,而是手动调用 iterator.next(),需注意:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
-
iterator.next()总是返回 Promise,即使迭代器内部同步yield,也要await它 - Promise 拒绝时,表示迭代器主动抛错(如上面
throw new Error),此时不应再继续调用next() - 可通过
iterator.return()提前终止(释放资源),或iterator.throw(err)向迭代器内部注入错误(较少用,适用于需通知生成器清理的状态)
示例(手动控制):
const iter = fetchPages('https://api.example.com/items');
let result;
while (!(result = await iter.next()).done) {
try {
await processChunk(result.value);
} catch (err) {
console.warn('Skip chunk due to processing error:', err);
continue;
}
}
if (result?.done === false) {
// 迭代器未完成就中断,可选调用 return()
await iter.return?.();
}
结合 ReadableStream 实现真实流式读取
浏览器或 Node.js(v16.7+)中,ReadableStream 原生支持异步迭代器接口([Symbol.asyncIterator]()),可直接 for await:
- 创建流后,用
stream.getReader()获取 reader,再用reader.read()循环读取Uint8Array块 - 更简单的方式:直接对 stream 使用
for await...of(需确保环境支持) - 错误由流自身触发(如网络中断),会作为
read()Promise 的拒绝被抛出,同样可被catch捕获
示例(Node.js 文件流):
import { createReadStream } from 'fs';
import { pipeline } from 'stream/promises';
<p>async function<em> readInChunks(stream, chunkSize = 64 </em> 1024) {
const reader = stream.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
// 分块切片(可选)
for (let i = 0; i </p><p>// 使用
const fileStream = createReadStream('./large.log');
for await (const chunk of readInChunks(fileStream)) {
console.log('Got chunk:', chunk.length, 'bytes');
}
</p>
不复杂但容易忽略:Async Iterator 的错误本质是 Promise 拒绝,不是同步异常;只要生成器内正确抛出、消费端用 for await 或正确 await next(),就能把“流式”和“容错”自然统一起来。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










