2012-09-18 83 views
9

可能重複:
Coordinating parallel execution in node.js異步內部循環中調用

首先,雙手放在僞代碼:

forEach(arrayelements) { 
    asyncQueryFunction(function(qres) { 
    //work with query results. 
    }); 
} 
// finally, AFTER all callbacks did return: 
res.render("myview"); 

如何做到這一點?

如果這還不夠清楚,我會解釋:

我需要做一系列的「更新」查詢(在MongoDB中,通過貓鼬),遍歷文件ID的列表。對於我的數組中的每個id,我將調用一個異步函數,它將返回查詢結果(實際上,我不需要對它們做任何事情)。

我知道我必須使用.forEach() JavaScript循環,但是隻有當我的所有異步查詢都完成後,如何才能執行我的「最終」回調?

我已經使用優秀的異步庫(https://github.com/caolan/async)來實現這種任務,當我執行一系列「有限」任務時。但我不認爲我可以通過它一系列不同的功能。

我可以嗎?

+0

這是一種方法:http://stackoverflow.com/questions/4631774/coordin ating-parallel-execution-in-node-js/4631909#4631909 – slebetman

+0

你可以使用異步流量控制庫,「async」是最流行的(https://github.com/caolan/async) –

回答

9

非常簡單的模式是使用「運行任務的計數器:

var numRunningQueries = 0 
forEach(arrayelements) { 
    ++numRunningQueries; 
    asyncQueryFunction(function(qres) { 
    //work with query results. 
    --numRunningQueries; 
    if (numRunningQueries === 0) { 
     // finally, AFTER all callbacks did return: 
     res.render("myview"); 
    } 
    }); 
} 

,或者可選地,使用異步輔助庫如Async.js

+0

假設我們有這段代碼在處理異步函數的某些請求中,可以說我們還有一個請求,那麼var numRunningQueries不會被覆蓋爲0? I – bana

+0

它在調用之前總是遞增並在完成時遞減。 JS中的節點是單線程的,這裏不存在競爭條件 –

+0

但是異步函數在單獨的線程中運行正確嗎?所以當我們完成數組時,會想到會發生什麼,但是aysnc函數仍在處理中,所以我認爲它會保留它的價值。我正在思考我猜想的事情。 – bana

2

如果我理解正確,asyncQueryFunction總是相同,因爲在您對每個文檔應用相同的更新。

我使用一個輔助方法保存後回調(只是交換了更新)多貓鼬文件(從CoffeeScript的轉換,所以它可能不會是完美的):

function saveAll(docs, callback) { 

    // a count for completed operations, and save all errors 
    var count = 0 
    , errors = []; 

    if (docs.length === 0) { 
    return callback(); 
    } else { 
    for (var i = 0; i < docs.length; i++) { 

     // instead of save, do an update, or asyncQueryFunction 
     docs[i].save(function(err) { 

     // increase the count in each individual callback 
     count++; 

     // save any errors 
     if (err != null) { 
      errors.push(err); 
     } 

     // once all the individual operations have completed, 
     // callback, including any errors 
     if (count === docs.length) { 
      return callback(errors); 
     } 
     }); 
    } 
    } 
}; 

saveAll(arrayElements, function(errors) { 
    // finally, AFTER all callbacks did return: 
    res.render("myview"); 
}