2016-04-26 66 views
2

我不知道是否有一种方法可以水ally地执行一组承诺?即我希望下一个承诺不会在当前承诺解决之前开始。执行一个Javascript数组承诺一个接一个解决

我的测试:

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 ] 
+0

@SkinnyJ,OP询问阻止'Promise',直到前一个解决.. – Rayon

回答

2

当你创建一个这样

[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) { 
    .... 
}); 

现在,我们通过一个创建的承诺之一,以前的承诺得到解决后,我们正在积累中res结果(实际上是result )。当所有的承诺都解决后,accumulatedResult将具有所有的价值。


注:强烈建议不要共享功能之间的数据。如果您需要,请确保您有充足的理由这样做。

+0

感谢您的答案。我有一个问题 - 如何触发一个承诺?它是由'()'还是'.then()'触发的?因为如果当我将它们赋值给数组''doItLater('a',100),doItLater('b',1),doItLater('c')]'时执行这些承诺,那么不应该如实结果每个“a”,“b”和“c”出现两次?例如类似'[1,b,c,a,2,b,c,a,...]',因为我已经执行了两次承诺。 –

+1

当您执行'doItLater('a',100)'时,异步操作启动并返回promise对象。所以当你执行'promiseList'时,我们只是处理'doItLater'返回的promise对象,异步操作不会再次触发。 – thefourtheye

+0

我认为OP实际上是在寻找'mapSeries',而不是'reduce' – Bergi

相关问题