2016-04-26 36 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