async/await 本身不直接处理流,但配合异步迭代器(如 for await...of)和可读流可实现大文件高效分块处理,核心是按需拉取、即时处理、及时释放内存,避免 OOM。

async/await 本身不直接处理流,但配合异步迭代器(如 for await...of)和可读流(ReadableStream 或 Node.js 的 fs.ReadStream),就能实现大文件的高效分块处理——每次只加载并处理一小块,避免内存爆满。
核心思路:用异步迭代器驱动流消费
关键不是“把整个文件读进内存”,而是让程序按需拉取、即时处理、及时释放。异步迭代器提供了一种同步风格的写法,背后却是非阻塞、背压友好的流式控制。
- 流对象(如
response.body、readline.createInterface()、或自定义异步生成器)必须实现[Symbol.asyncIterator]方法,才能被for await...of消费 -
async/await用于在循环体内处理每个数据块的异步逻辑(如解析 JSON、写入数据库、校验内容),而不会阻塞后续块的读取准备 - 整个流程必须包裹在
async函数中,否则for await...of会报语法错误
浏览器中处理 fetch 响应流(按 chunk 解析)
适合下载日志、CSV、大型 JSONL 等文本流:
async function processTextStream(url) {
const response = await fetch(url);
const reader = response.body.getReader();
const decoder = new TextDecoder();
<p>for await (const chunk of streamAsyncIterator(reader, decoder)) {
// 每次 chunk 是一个字符串片段,可按行分割或累积缓冲
console.log('Received chunk:', chunk.length, 'bytes');
// 例如:split('\n').forEach(line => handleLine(line))
}
}</p><p>// 封装成可迭代的异步生成器
async function* streamAsyncIterator(reader, decoder) {
while (true) {
const { done, value } = await reader.read();
if (done) break;
yield decoder.decode(value, { stream: true });
}
Node.js 中逐行读取大文件(内存友好)
这是最典型的大文件场景,避免 fs.readFileSync 或 fs.readFile 导致 OOM:
立即学习“Java免费学习笔记(深入)”;
import * as fs from 'fs/promises';
import * as readline from 'readline';
<p>async function processLargeFile(filePath) {
const file = await fs.open(filePath);
const stream = file.createReadStream();
const rl = readline.createInterface({ input: stream });</p><p>// rl 是原生的 AsyncIterable,可直接 for await
for await (const line of rl) {
// 每次只有一行在内存中
const data = JSON.parse(line); // 示例:处理 JSONL
await saveToDatabase(data); // 异步保存,不影响下一行读取
}</p><p>await file.close();
}
-
readline.createInterface返回的对象自带[Symbol.asyncIterator],无需额外封装 -
for await内部自动调用.next()并等待 Promise,你只需专注业务逻辑 - 记得关闭文件句柄(
file.close()),推荐用try/finally包裹确保清理
自定义分块读取(按字节大小控制)
当需要精确控制块大小(如每次 64KB),可手动封装异步生成器:
async function* readInChunks(fileHandle, chunkSize = 65536) {
let offset = 0;
const buffer = new Uint8Array(chunkSize);
<p>while (true) {
const { bytesRead } = await fileHandle.read(buffer, 0, bytesRead, offset);
if (bytesRead === 0) break;
yield buffer.slice(0, bytesRead);
offset += bytesRead;
}
}</p><p>// 使用
async function handleChunkedFile(filePath) {
const fh = await fs.open(filePath);
try {
for await (const chunk of readInChunks(fh)) {
await processBinaryChunk(chunk); // 如哈希计算、图像缩略
}
} finally {
await fh.close();
}
}
这种模式对二进制处理、加密、校验等场景更灵活,且完全可控。


















