You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求类似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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 12:13:14