2014-10-10 196 views
0

異步編程比同步編程困難得多。NodeJS:for循環和承諾

使用的NodeJS,我想以下幾點:

for (var i = 0; i < 10; i++) { 
    someFunction().then(function() { 
     // Do stuff 
    }); 
} 

但我希望在做的東西的一部分已經完成了迴路只能繼續。

任何想法如何輕易實現...?

謝謝!

回答

2

異步編程可能會造成混淆,但大多數的混亂是可以消除,如果你記住的東西保持像回調和then將在稍後的時間運行,代碼後它們包含的塊已經完成。

Promise庫,async模塊,都試圖獲得更多的控制程序的流量。這裏有一個解釋不同方法的解決方案,通過查看針對同一問題的不同解決方案,幫助我理解事物。

其他一些答案提到Q.all()。如果你已經有了一系列的承諾,這個效果很好。

如果您有一組值或承諾,還有另一個庫使得這更容易,名爲bluebird。它有一個名爲.map()的方法,您可以使用該方法與數組一起啓動承諾鏈。

使用這種方法,您不需要調用異步,promise返回函數,將返回的promise保存在數組中,然後將該數組傳遞給Q.all。它爲您節省了一些步驟。

因此,假設您擁有的只是一個數組值:

var items = [0,1,2,3,4,5,6,7,8,9];

你可以做類似如下:

Promise.map(items, function (item) { 
    return performAsyncOperation(item); 
}, {concurrency: n}) 
.then(function(allResults){ 
    // 'allResults' now contains an array of all 
    // the results of 'performAsyncOperation' 
}) 

注意:對於這個達到預期效果, performAsyncOperation必須返回承諾

還請注意Promise.map()的第三個參數:{concurrency: n}。如果指定了這個選項,bluebird將只允許一次執行n操作,如果您有大量要處理的項目會對系統造成壓倒,如果它們全部被啓動(網絡連接,文件句柄等)。

最後說明:這裏是bluebird API doc。這本書寫得非常好,有很多例子,也是探索承諾如何幫助您輕鬆生活的絕佳方式。

希望它有幫助!

1

使用Q.all等待所有承諾繼續

2

要擴大Anders的答案之前解決,這是怎麼了,我的過去的情況需要被期待已久的多個承諾處理這樣的:

var promises = []; 

for (var i = 0; i < 10; i++) { 
    promises.push(someFunction().then(function() { 
      // Do stuff 
     }) 
    ); 
} 

Q.all(promises) 
.then(function() { 
    // Do all the things! 
}) 
+0

看來,OP可能希望執行承諾的啓動順序,換句話說,只有當第一個完成時才啓動第二個進程。 – 2014-10-10 11:36:06

1

你可以鏈你的承諾與reduce

array.reduce(function(promise, elt) { 
    return promise.then(function() { return long_process(elt); }); 
}, new Promise.resolve()); 

這個表達式的結果將是操作的順序已經完成的承諾。這些代碼不是隻調用十個異步操作並等待它們全部完成,而是等到第一個操作完成後再啓動第二個操作,如果這很重要的話。

2

我喜歡在這種情況下使用的模式是定義一個函數,在異步操作完成後調用它自己。你的例子是在該行:

var times = 10; 
var current = 0; 

(function nextLap() { 
    if (current >= times) { 
     return callback(); 
    } 

    ++current; 

    someFunction() 
    .then(function() { 
     // do stuff 
     nextLap(); 
    }) 
    .catch(callback); 
})();