【问题标题】:Execute an array of Javascript promises one after one resolved一个接一个地执行一系列 Javascript 承诺
【发布时间】:2016-04-26 12:20:04
【问题描述】:

我想知道是否有一种方法可以瀑布式地执行一系列承诺?即,我希望在当前的承诺解决之前不要开始下一个承诺。

我的测试:

import Promise from 'bluebird'

describe('promises waterfall', () => {
  const result = []
  function doItLater(val, time = 50) => {
    return new Promise(resolve => {
      setTimeout(() => {
        result.push(val)
        resolve(val)
      }, time)
    })
  }

  it('execute promises one after one resolved', done => {
    result.push(1)
    const promiseList = [doItLater('a', 100),doItLater('b', 1),doItLater('c')]
    result.push(2)

    Promise.each(
      promiseList,
      (output) => {
        result.push(output + '-outputted')
      }
    )
      .then(
        () => {
          result.push(3)
          console.log(result)
          expect(result).to.eql([ 1, 2, 'a', 'b', 'c', 'a-outputted', 'b-outputted', 'c-outputted', 3 ])
          done()
        }
      )
  })
})

更新

对不起,如果我把它弄得太混乱了。我在问如何使我的测试通过。目前我的测试失败 - 实际结果顺序错误:

[ 1,
  2,
  'b',
  'c',
  'a',
  'a-outputted',
  'b-outputted',
  'c-outputted',
  3 ]

【问题讨论】:

  • @SkinnyJ,OP 询问是否要阻止 Promise,直到解决前一个问题..

标签: javascript asynchronous promise bluebird reduce


【解决方案1】:

当你创建这样的承诺时

[doItLater('a', 100),doItLater('b', 1),doItLater('c')]

它们已经在异步执行。无法控制它们的执行顺序。

您可以将Promise.reduce 用于您的情况,就像这样

Promise.reduce([['a', 100], ['b', 1], ['c']], function(res, args) {
    return doItLater.apply(null, args).then(function(output) {
        res.push(output + '-outputted');
        return res;
    });
}, result)
.then(function(accumulatedResult) {
    ....
});

现在,我们正在一个一个地创建 Promise,在之前的 Promise 解决之后,我们将结果累加到 res(实际上是 result)。当所有的承诺都被解决后,accumulatedResult 将拥有所有的值。


注意:强烈建议不要在函数之间共享数据。如果必须这样做,请确保您有令人信服的理由这样做。

【讨论】:

  • 感谢您的回答。我有一个问题 - 如何触发承诺?是() 还是.then() 触发的?因为如果如您所说,当我将它们分配给数组[doItLater('a', 100),doItLater('b', 1),doItLater('c')] 时执行承诺,那么实际结果不应该是'a''b''c' 中的每一个出现两次吗?例如[1, b, c, a, 2, b, c, a, ...] 之类的东西,因为我已经执行了两次承诺?
  • 当您执行doItLater('a', 100) 时,异步操作开始并返回promise 对象。所以当你做promiseList时,我们只是在处理doItLater返回的promise对象,不会再次触发异步操作。
  • 我认为 OP 实际上是在寻找 mapSeries,而不是 reduce
  • @Bergi 我实际上也尝试过mapSeries,它给了我完全相同的错误订单结果。我可能以错误的方式使用它。
  • @IvanWang 由于您在问题中使用了 ES6 语法,因此您可以使用扩展运算符,例如 doItLater(...args)
【解决方案2】:
// Promisse waterfall pattern
var promises = [1,2,3].map((guid)=>{
    return (param)=> {
      console.log("param", param);
      var id = guid;
      return new Promise(resolve => {
        // resolve in a random amount of time
        setTimeout(function () {
          resolve(id);
        }, (Math.random() * 1.5 | 0) * 1000);
      });
    }
}).reduce(function (acc, curr, index) {
  return acc.then(function (res) {
    return curr(res[index-1]).then(function (result) {
      console.log("result", result);
      res.push(result);
      return res;
    });
  });
}, Promise.resolve([]));
promises.then(console.log);

【讨论】:

    猜你喜欢
    • 2016-02-01
    • 2017-11-09
    • 2018-04-28
    • 2013-11-25
    • 1970-01-01
    • 2013-12-22
    • 2013-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多