与承诺小组合作

时间:2017-09-13 11:11:10

标签: javascript node.js promise

我很难理解如何与需要共同解决的承诺小组合作。

在我的情况下,我想基于一组id进行一系列的promise调用,并有选择地将它们添加到输出数组中。如果这是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。

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

4 个答案:

答案 0 :(得分: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可以被认为是将一个容器从里面翻出来:你给它一个Promises数组(通过在一个输入数组上映射你的promise-returns函数),它给你一个数组的Promise然后你像任何其他数组一样处理的结果。

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

由于在决定是否保留结果之前对每个输入进行了全面处理,因此只需处理两个异步步骤的输入,然后在一切结算后过滤生成的数组就不会受到惩罚。 / p>

答案 1 :(得分:1)

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

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允许您将任何数组映射到promises数组中,并生成一个新的promise,一旦解决了所有这些promise,就会解析它。在映射函数中,您可以链接两个promise。

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

您可以使用 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
});