【问题标题】:Fastest way of processing a nested tree of promises in javascript?在javascript中处理嵌套的承诺树的最快方法?
【发布时间】:2019-02-26 06:58:11
【问题描述】:

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

  1. 该进程应返回一个仅在所有嵌套作业都完成时才解析的承诺。
  2. 同一级别的每个作业都需要按顺序处理,但子级可以并行处理。
  3. 我不能使用等待/异步。

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

    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)`);
            });
    })();

当我在我的网络控制台中运行它时,我得到以下结果:

30 (took 2.839s)

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

是这样吗?如果是这样,您将如何重写示例以利用该方法?如果没有,一般来说有没有更快的方法?

【问题讨论】:

  • 并行?在单线程语言中?这意味着什么?
  • "同层的每个job都需要按顺序处理,但是children可以并行处理。" - 没明白。孩子们在同一水平,对吧?
  • @RichBrowne 是的,但是您希望同时处理树的哪些部分?你说连续的节点需要顺序处理,但是子节点不也是连续的吗?你的意思是不同父节点的子节点?假设我会简单地一次处理所有内容,您到底想在哪里引入依赖项?
  • 是的,我正在努力解决不并发的问题。是不是只有根节点必须串联,但之后任何级别的所有子节点都可以并发。 ?例如。 numbers 2,1,2,4,5 可以,但2,1,2,5,4 不行
  • 但是按照这个定义,这不就意味着一切都必须按顺序处理吗?例如。做第一个top 1层,直到第一个的孩子都做完才能做下一个,然后第一层的孩子也需要按顺序排列。

标签: javascript promise


【解决方案1】:

在启动子作业后立即解决父级问题,然后再对结果求和会更快吗?

是的,会的。如果理解正确,您可能希望只按顺序处理兄弟节点,并让每个节点在开始其子节点的工作之前等待其前任节点,而不是让节点等待其子节点完成。

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

是的,这会更快,但并不显着 - 最多是一个常数因素。您仍然需要按顺序处理树的所有叶子。

不过,这方面的代码很简单 - 您只需将 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,所以我想知道您为什么要获取任何东西:-)

【讨论】:

  • 感谢@Bergi。
猜你喜欢
  • 2018-12-03
  • 2014-12-05
  • 1970-01-01
  • 1970-01-01
  • 2019-02-24
  • 1970-01-01
  • 2020-03-29
  • 2018-07-19
  • 2019-12-25
相关资源
最近更新 更多