2014-12-05 156 views
1

一個nodejs項目。我試着用承諾運行大量(大約100k)任務。我可以做的是將它轉換爲Q的workOnebyOne函數。有沒有更好的方法來做到這一點?按順序運行大量的承諾

function workOnebyOne(items, worker) { 
    var deferred = Q.defer() 

    function _doNext() { 
    if (items.length === 0) { 
     deferred.resolve() 
     return 
    } 
    var item = items[0] 
    synchronize(worker, item) 
     .then(function (result) { 
     items = items.slice(1) 
     deferred.notify({ 
      item: item, 
      result: result 
     }) 
     _doNext() 
     }, function() { 
     items = items.slice(1) 
     _doNext() 
     }) 
    } 

    _doNext() 

    return deferred.promise 
} 

utils.workOnebyOne(tasks, workerFunction) 
+0

使用索引而不是切片數組可能會更有效。 – 2014-12-05 16:02:19

+1

你的分號鑰匙壞了嗎? – jfriend00 2014-12-05 18:43:03

+0

'synchronize()'做了什麼? – Bergi 2014-12-13 12:44:14

回答

2

你基本上是在這裏重新實施排隊。在藍鳥承諾(這也是更快,消耗更少的內存,這有助於100K任務),你會使用Promise.each

在Q中,您通常可以在任務數組上使用.reduce將它們一次排隊 - 然而,使用100K元素在Q promise中創建100K承諾隊列會導致節點崩潰(同樣,這是Q,藍鳥或承諾時)它就好)。這(這裏不正確)解決方案看起來是這樣的:

var res = tasks.reduce(function(p, c){ 
    return p.then(function(){ return workerFunction(c); }); 
}, Q()); 

對於短隊列(< 500許諾Q)這工作得很好。

因此,由於舊的圖書館的選擇,並且由於涉及大量的承諾,您不能現實地解決它的優雅,使用類似回調隊列的方法非常接近您唯一的方式。我也避免notify,因爲它被刪除(甚至從Q),並且通常是一個糟糕的API(編寫不好)。

+0

只是好奇,究竟是什麼崩潰Q有很長的承諾序列?你在手邊有問題的鏈接? – Bergi 2014-12-13 12:47:37

+0

這很簡單 - Bluebird也會發生同樣的情況(儘管承諾數量更多,甚至更多的功能(更高的門檻)),它只消耗太多內存。內存比藍鳥承諾使用位標誌的狀態 – 2014-12-13 12:50:23

+0

啊,我認爲它會受到調用堆棧或類似的限制 – Bergi 2014-12-14 11:00:11

1

我花了一些時間尋找簡單而優雅的解決方案。我發現只有一些提示和討論,但沒有現成的例子。最後,我發現在https://github.com/kriskowal/q/issues/606,結果什麼都爲我工作可以分離和推廣這樣的討論:

function workOneByOne(items, someAsyncFuntionReturningPromise) { 
    var lastResultPromise = items 
    .map(function(item) { 
     return function(previousResult) { 
     /* 
     * this function has to: 
     * - process result from previous item processed if any 
     * - call the async job 
     * - return promise of the job done 
     */ 
     if (previousResult) { 
      // process result here 
     } 

     return someAsyncFuntionReturningPromise(item); 
    }}) 
    .reduce(Q.when, Q()); 

    return lastResultPromise; 
} 

並且如果沒有可用的函數返回的承諾,你可以撥打上面

workOneByOne(items, Q.nfbind(someAsyncFunctionWithCallback)) 
+0

呃,那不應該是'someAsyncFunctionWithCallback'。爲什麼不'someAsyncFuntionReturningPromises'? – Bergi 2015-03-10 14:03:58

+0

有時候它可能是一些沒有任何承諾的外部功能。例如,我的具體情況是,我最初使用節點http請求,它們不是承諾。然後我轉向q-io,所以可以按照您的建議返回承諾。但爲了防止上面提出的解決方案考慮到'someAsyncFunctionWithCallback'的cas;) – ciekawy 2015-03-10 14:54:40

+1

這種情況應該由['Q.nfbind']解決(https://github.com/kriskowal/q/wiki/API-Reference #qnfbindnodefunc-args)。 – Bergi 2015-03-10 14:57:50