全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-16 7 分钟 ✍️ juanwangdev

JavaScript 异步迭代器与 for await...of

异步迭代器用于遍历异步数据源,for await...of 是异步版本的 for...of,自动等待每个迭代值解析。

异步迭代器基础

JavaScript
// 同步迭代器:Symbol.iterator
const syncIterable = {
    [Symbol.iterator]() {
        let i = 0;
        return {
            next() {
                if (i < 3) return { value: i++, done: false };
                return { done: true };
            }
        };
    }
};

// 异步迭代器:Symbol.asyncIterator
const asyncIterable = {
    [Symbol.asyncIterator]() {
        let i = 0;
        return {
            async next() {  // async next 方法
                if (i < 3) {
                    await new Promise(r => setTimeout(r, 100));  // 模拟异步
                    return { value: i++, done: false };
                }
                return { done: true };
            }
        };
    }
};

for await...of 语法

JavaScript
// 必须在 async 函数中使用
async function consumeAsyncIterable() {
    for await (const value of asyncIterable) {
        console.log(value);  // 0, 1, 2(自动等待)
    }
}

consumeAsyncIterable();

// 等价于手动迭代
async function manualIterate() {
    const iterator = asyncIterable[Symbol.asyncIterator]();
    let result;
    while (!(result = await iterator.next()).done) {
        console.log(result.value);
    }
}

异步生成器函数

JavaScript
// async generator:最简单的异步迭代器实现
async function* asyncGenerator() {
    yield await Promise.resolve(1);
    yield await Promise.resolve(2);
    yield await Promise.resolve(3);
}

(async () => {
    for await (const value of asyncGenerator()) {
        console.log(value);  // 1, 2, 3
    }
})();

// 模拟流式数据
async function* fetchChunks(url) {
    const response = await fetch(url);
    const reader = response.body.getReader();
    while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        yield value;  // 逐块产出
    }
}

// 处理分页数据
async function* fetchPages(baseUrl) {
    let page = 1;
    while (true) {
        const response = await fetch(`${baseUrl}?page=${page}`);
        const data = await response.json();
        if (data.items.length === 0) break;
        yield data.items;
        page++;
    }
}

(async () => {
    for await (const items of fetchPages('/api/products')) {
        console.log('收到数据:', items);
    }
})();

异步迭代器返回方法

JavaScript
async function* generator() {
    try {
        yield 1;
        yield 2;
        yield 3;
    } finally {
        console.log('清理资源');  // return 时执行
    }
}

(async () => {
    const gen = generator();
    console.log(await gen.next());  // { value: 1, done: false }

    // 提前终止,触发 finally
    await gen.return('手动终止');
    console.log(await gen.next());  // { value: undefined, done: true }
})();

// throw 方法
(async () => {
    const gen = generator();
    await gen.next();
    await gen.throw(new Error('迭代器错误'));  // 抛出错误
})();

与同步迭代器对比

JavaScript
// 同步迭代器
const sync = {
    [Symbol.iterator]() {
        return {
            next() {
                return { value: 1, done: false };  // 直接返回值
            }
        };
    }
};

for (const v of sync) {
    console.log(v);  // 立即输出
}

// 异步迭代器
const async = {
    [Symbol.asyncIterator]() {
        return {
            async next() {
                return { value: await Promise.resolve(1), done: false };  // 返回 Promise
            }
        };
    }
};

// 需要 async 环境
(async () => {
    for await (const v of async) {
        console.log(v);  // 等待后输出
    }
})();
特性同步迭代器异步迭代器
SymbolSymbol.iteratorSymbol.asyncIterator
next() 返回{ value, done }Promise<{ value, done }>
遍历语法for...offor await...of
迭代器方法普通 next()async next()

实际应用场景

JavaScript
// 读取流数据
async function readStream(stream) {
    const chunks = [];
    for await (const chunk of stream) {
        chunks.push(chunk);
    }
    return Buffer.concat(chunks);
}

// 处理事件序列(Node.js)
const { EventEmitter } = require('events');

async function* eventsToAsyncIterator(emitter, eventName) {
    const queue = [];
    const resolveQueue = [];

    emitter.on(eventName, (data) => {
        if (resolveQueue.length) {
            resolveQueue.shift()(data);
        } else {
            queue.push(data);
        }
    });

    while (true) {
        if (queue.length) {
            yield queue.shift();
        } else {
            yield await new Promise(resolve => resolveQueue.push(resolve));
        }
    }
}

// 批量异步处理
async function* batchProcess(items, batchSize) {
    for (let i = 0; i < items.length; i += batchSize) {
        const batch = items.slice(i, i + batchSize);
        yield await Promise.all(batch.map(processItem));
    }
}

(async () => {
    for await (const results of batchProcess([1,2,3,4,5,6], 2)) {
        console.log('批次结果:', results);
    }
})();

注意事项

  • for await...of 必须在 async 函数内使用
  • 异步迭代器不能用普通 for...of 遍历
  • 异步生成器函数必须用 async function* 定义
  • 提前终止会触发 finally 块执行清理
JavaScript
// 错误:同步遍历异步迭代器
for (const v of asyncIterable) {
    console.log(v);  // TypeError: asyncIterable is not iterable
}

// 正确:异步遍历
(async () => {
    for await (const v of asyncIterable) {
        console.log(v);
    }
})();

// 异步迭代器可以同步 next(),但返回 Promise
const iterator = asyncIterable[Symbol.asyncIterator]();
iterator.next();  // 返回 Promise,不是 { value, done }

要点总结

  • 异步迭代器使用 Symbol.asyncIterator 定义,next() 返回 Promise
  • for await...of 自动等待每个迭代值,必须在 async 函数内使用
  • 异步生成器 async function* 是最简洁的异步迭代器实现
  • 异步迭代器支持 return()throw() 方法
  • 适用于流数据处理、分页数据、事件序列等异步数据源
  • 提前终止触发 finally,适合资源清理场景

📝 发现内容有误?点击此处直接编辑

← 上一篇 JavaScript 并发控制(Promise.all、Promise.race、Promise.allSettled)
下一篇 → JavaScript 包管理工具(npm、yarn)
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库