求类似p-props/p-all的递归Promise解析工具(支持并发控制)
递归解析Promise并控制并发的实现方案
问题描述
需要实现类似p-props、p-all的功能,但支持递归解析Promise,示例代码如下:
const values = { a: () => Promise.resolve(1), b: [() => Promise.resolve(2)], c: { d: () => Promise.resolve(3), }, }; console.log(await resolve(values, { concurrency: 2}));
调用后期望得到结果{a: 1, b: [2], c: {d: 3}},且同一时间仅运行2个Promise。考虑结合p-all、p-props/p-map及它们的映射器实现,但不确定并发控制的处理方式,询问是否有现成方案?
实现方案
目前没有完全匹配的开箱即用库,但可以基于p-all和递归遍历逻辑快速实现核心功能,核心思路是统一收集所有异步任务,用p-all的并发控制能力统一调度,同时保持原结构的层级。
代码实现
import pAll from 'p-all'; function resolve(obj, { concurrency }) { const tasks = []; const result = Array.isArray(obj) ? [] : {}; // 递归遍历结构,收集异步任务并初始化结果结构 function traverse(item, path) { if (typeof item === 'function') { tasks.push({ fn: item, path }); return; } if (typeof item === 'object' && item !== null) { for (const key in item) { if (Object.prototype.hasOwnProperty.call(item, key)) { const newPath = [...path, key]; // 同步初始化结果的层级结构 result[key] = Array.isArray(item[key]) ? [] : {}; traverse(item[key], newPath); } } return; } // 非异步值直接赋值到结果对应位置 setValue(result, path, item); } // 根据路径将值写入结果结构 function setValue(target, path, value) { let current = target; for (let i = 0; i < path.length - 1; i++) { current = current[path[i]]; } current[path[path.length - 1]] = value; } // 启动遍历收集任务 traverse(obj, []); // 用p-all控制并发执行所有任务,完成后返回结果 return pAll( tasks.map(task => async () => { const value = await task.fn(); setValue(result, task.path, value); }), { concurrency } ).then(() => result); } // 测试示例 const values = { a: () => Promise.resolve(1), b: [() => Promise.resolve(2)], c: { d: () => Promise.resolve(3), }, }; resolve(values, { concurrency: 2 }).then(console.log); // 输出: { a: 1, b: [ 2 ], c: { d: 3 } }
关键说明
- 统一并发池:所有异步任务会被收集到一个队列,通过
p-all严格控制并发数,避免多层结构各自控制并发导致的总数超标 - 结构一致性:遍历过程中同步初始化结果的层级结构,任务执行完成后精准回填结果,完全保留输入的对象/数组层级
- 扩展性:如果需要支持直接传入Promise(而非返回Promise的函数),只需在
traverse中添加item instanceof Promise的判断,将其包装成函数即可
内容的提问来源于stack exchange,提问作者TigrisC
相关产品推荐
相关产品推荐

