如何实现类似Promise.any的多异步Generator并发取值?
实现多异步生成器的并发输出
你需要的是一个能并发监听多个异步生成器、只要有生成器产出值就立即向外输出、直到所有生成器耗尽的工具函数,类似你设想的Generator.any但不会中途终止其他生成器。
核心实现思路
通过Promise.race跟踪所有活跃生成器的下一次产出请求,每次拿到最先完成的结果后,将该生成器的下一次产出请求重新加入监听队列,循环直到所有生成器都处理完毕。
具体代码实现
// 实现需求的合并异步生成器工具函数 async function* mergeAsyncGenerators(generators) { // 初始化所有生成器的首次next请求Promise const pendingPromises = generators.map(async gen => { const result = await gen.next(); return { gen, result }; }); while (pendingPromises.length > 0) { // 等待第一个完成的产出请求 const { gen, result } = await Promise.race(pendingPromises); // 移除当前已完成的Promise const targetIndex = pendingPromises.findIndex(p => p === (async () => ({ gen, result }))() ); pendingPromises.splice(targetIndex, 1); // 如果生成器未耗尽,添加下一次next请求 if (!result.done) { pendingPromises.push(async () => { const nextResult = await gen.next(); return { gen, result: nextResult }; }()); } // 立即产出当前获取到的值 yield result.value; } } // 模拟你的values异步生成器(带随机延迟体现并发效果) async function* values(input) { await new Promise(resolve => setTimeout(resolve, Math.random() * 1000)); yield `输入${input}的第一个值`; await new Promise(resolve => setTimeout(resolve, Math.random() * 1000)); yield `输入${input}的第二个值`; } // 你的包装生成器函数 async function* generateValues() { const inputs = [1,2,3,4,5]; const generators = inputs.map(input => values(input)); // 使用合并函数实现并发输出 for await (const value of mergeAsyncGenerators(generators)) { yield value; } } // 测试调用 (async () => { for await (const val of generateValues()) { console.log(val); } })();
代码说明
mergeAsyncGenerators函数:- 启动阶段为每个生成器创建首次
next()请求的Promise - 循环通过
Promise.race抢占式获取最先完成的产出结果 - 未耗尽的生成器会被持续加入下一轮监听,保证所有结果都能被收集
- 拿到结果后立即向外产出,完全符合“有值就输出”的需求
- 启动阶段为每个生成器创建首次
测试效果:
由于values函数加入了随机延迟,运行时会看到不同输入的结果交替输出,而非按输入顺序串行输出所有内容。
内容的提问来源于stack exchange,提问作者Mahesh Bansod
相关产品推荐
相关产品推荐

