在JavaScript中处理诺言的嵌套树的最快方法?

时间:2019-02-25 14:13:02

标签: javascript promise

我正在尝试找出处理嵌套的作业树的最快方法,这些作业会在javascript中返回promise。我具有以下条件:

  1. 该过程应返回一个仅在所有嵌套作业完成后才能解决的承诺。
  2. 同一级别的每个作业都需要顺序处理,但是子级可以并行处理。
  3. 我不能使用await / async。

我已经模拟了一个示例,该示例将一堆数字求和,并调用一个公共Web服务来模拟实际工作(不幸的是,由于无法通过https使用公共Web服务,因此我无法对此进行编码):

    function sumNumbers(numbersToSum) {
        return numbersToSum.reduce((p, current) => {
            return p.then(runningTotal => {
                return fetch(`http://numbersapi.com/${current.number}/`)
                    .then(result => {
                        var parentTotal = runningTotal + current.number;
                        if (current.children && current.children.length > 0) {
                            return sumNumbers(current.children)
                                .then(childrenTotal => {
                                    return childrenTotal + parentTotal;
                                });
                        }
                        else {
                            return parentTotal;
                        }
                    });
            });
        }, Promise.resolve(0));
    }

    var numbers = [
        {
            number: 2,
            children: [
                { number: 1 },
                {
                    number: 3,
                    children: [
                        { number: 2 },
                        {
                            number: 1,
                            children: [
                                { number: 1 },
                                { number: 2 }
                            ]
                        }
                    ]
                },
                { number: 2 }
            ]
        },
        { number: 4 },
        { number: 5 },
        {
            number: 3,
            children: [
                {
                    number: 1,
                    children: [
                        { number: 1 }
                    ]
                },
                { number: 2 }
            ]
        }
    ];

    (() => {
        var startTime = new Date();
        sumNumbers(numbers)
            .then(total => {
                var finishTime = new Date();
                console.log(`${total} (took ${((finishTime - startTime) / 1000)}s)`);
            });
    })();

当我在Web控制台中运行该命令时,会得到以下结果:

30 (took 2.839s)

此方法有效,但是当作业中有孩子要处理时,父级会等待子级作业完成,然后再解决并继续下一个同级作业。我想知道并行处理子作业是否会更快?

是这种情况吗?如果是这样,您将如何重写示例以利用该方法?如果没有,那么通常有更快的方法吗?

1 个答案:

答案 0 :(得分:2)

  

启动子项工作后立即解决父项问题,然后再将结果求和会更快吗?

是的,会的。如果理解正确,您将只希望顺序处理同级节点,并让每个节点在开始其子节点的工作之前等待其前任节点,而没有一个节点在等待其子节点完成。

  

或更明确地说,从第一级进行的第一次读取与从第二,第三和第四级进行的第一次读取同时执行。这是4个并行执行而不是串行执行的请求(如op中的示例代码所示),当扩展到更大的示例时,肯定会节省大量时间。

是的,这会更快,但不会显着-最多是一个常数。您仍然必须顺序处理树上的所有叶子。

尽管这样的代码很简单-您只需将fetch(node).then(processChildren)替换为并发版本:

return Promise.all([
    fetch(`http://numbersapi.com/${current.number}/`),
    current.children && current.children.length > 0
      ? sumNumbers(current.children)
      : 0
}).then(([result, childrenTotal]) => {
//        ^^^^^^
    var parentTotal = runningTotal + current.number;
    return childrenTotal + parentTotal;
});

我注意到您从未真正使用过result,所以我想知道为什么您根本不获取任何东西:-)