【问题标题】:Working with groups of promises使用承诺组
【发布时间】:2018-02-22 01:45:31
【问题描述】:

我很难理解如何处理需要一起解决的承诺组。

在我的情况下,我想根据一组 id 进行一系列承诺调用,并有选择地将它们添加到输出数组中。如果这是 PHP,我会这样做:

$output = []
foreach($input as $id) {

  $result1 = functioncall1($id);
  $result2 = functioncall2($result1);

  if ($result2 == 'some filter') {
    $output[] = $result1;
  }
}

这不能通过异步调用来完成,因为循环不会等待结果返回。所以我像这样使用蓝鸟的承诺:

Promise.map(input, function(id) {
    promisifedFunction1(id)
      .then(function(result1) {
          //process result1 some more

          promisifedFunction2(result1)
            .then(function(result2) {
                //process result2 some more

                if (result2 == 'some filter') {
                  return result1;
                });

            });

      })
  .then(function(output) {});
}

我显然在这里遗漏了一些东西,因为我的输出只包含一个未定义的数组。然而,当我期望它时,它显然是映射并达到最终结果,并且只有在过滤正常时才会生成那些未定义的数组。即使过滤器只返回一个文字字符串,也会产生 undefined。

我正在清除遗漏的东西,但我正在努力填补空白。

【问题讨论】:

标签: javascript node.js promise


【解决方案1】:

我认为这在 SO 上已经有了答案,但显然它没有(或者如果它进行了几次快速搜索并没有找到它)。

你想要这样的结构:

let filteredResults = Promise.all(arr.map(x => promisifiedFn1(x)))
  .then(xs => xs.map(result1 => promisifiedFn2(result1)))
  .then(ys => ys.filter(someFilteringFn));

Promise.all 可以被认为是把一个容器从里到外:你给它一个 Promise 数组(通过将你的 promise-returning 函数映射到一个输入数组上),它给你一个 Promise 数组然后您将其视为任何其他数组的结果。

所以xs 是第一个函数的结果数组,一旦它全部解析,就会映射到输入上。 ys 是第二个。我不确定 bluebird 的 Promise.map 是做什么的,但您可以将我代码中的前两个步骤与它结合起来。

由于您在决定是否保留结果之前对每个输入进行了全面处理,因此只需使用两个异步步骤处理输入,然后在一切解决后过滤结果数组,就不会受到任何惩罚。

【讨论】:

    【解决方案2】:

    确保您的承诺功能正常,这也应该有效:

    var elements = ["one", "two", "three"]
    var container = document.querySelector('.results')
    
    function promisifiedFunc1(arrayElement) {
      return new Promise(function(resolve, reject) {
        setTimeout(function() {
          resolve('input to the next func ' + arrayElement)
        }, 1000)
      })
    }
    
    function promisifiedFunc2(inputFromPreviousFunc) {
      return new Promise(function(resolve, reject) {
        container.innerHTML += "<br>" + inputFromPreviousFunc
        setTimeout(function() {
          resolve('some filter')
        }, 1000)
      })
    
    }
    
    Promise.map(elements, function(one) {
        return promisifiedFunc1(one).then(promisifiedFunc2);
      })
      .filter(function(res2) {
        return res2 === 'some filter';
      })
      .then(function(allResults) {
        console.log(allResults);
        container.innerHTML += "<br>All Done!";
      })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.5.0/bluebird.min.js"></script>
    <div class="results"></div>

    Promise.map 允许您将任何数组映射到一个 promise 数组,并生成一个新的 promise,一旦所有这些 promise 都解决,该 promise 就会被解决。在映射函数中,您可以将两个 Promise 链接起来。

    【讨论】:

      【解决方案3】:

      您可以进行 eta-reduction 以使该代码看起来更简单:

      Promise.map(input, promisifedFunction1)
             .map(promisifiedFunction2)
             .filter(v => v === 'someFilter')
             .then(outputFunction);
      

      【讨论】:

        【解决方案4】:

        您可以使用 Promise.all

        var promise1 = new Promise(function (resolve, reject) {
            // promise1 code here
            resolve(true);
        })
        var promise2 = new Promise(function (resolve, reject) {
            // promise2 code here
            resolve(true);
        })
        var promise3 = new Promise(function (resolve, reject) {
            // promise3 code here
            resolve(true);
        })
        

        这里我们使用了 3 个 Promise,现在如果我们必须在解决所有 Promise 后执行代码,我们可以使用 Promise.all

        Promise.all([promise1, promise2, promise3]).then(() => {
            // code
        });
        

        【讨论】:

          猜你喜欢
          • 2016-07-27
          • 2016-03-04
          • 2013-10-06
          • 2016-07-24
          • 1970-01-01
          • 2018-10-03
          • 2017-10-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多