Sebelum saya jelaskan lebih lanjut, saya ingin mencatat bahwa ada bug dalam kode Anda:
function(err_positive, result_positive) {
result_positive.count(function(err, count){
console.log("Total matches: " + count);
positives[i] = count; // <--- BUG: i id always 5 because it
}); // is captured in a closure
}
Masalah penutupan &loop klasik. Lihat:Silakan jelaskan penggunaan penutupan JavaScript dalam loop
Sekarang, bagaimana menangani fungsi asinkron dalam loop. Ide dasarnya adalah Anda perlu melacak berapa banyak panggilan asinkron yang telah selesai dan menjalankan kode Anda setelah panggilan terakhir kembali. Misalnya:
var END=5;
var counter=end;
for (var i=0;i<END; i++) {
collection.find(
{value:1},
{created_on:
{
$gte:startTime + (i*60*1000 - 30*1000),
$lt: startTime + (i*60*1000 + 30*1000)
}
},
(function(j){
return function(err_positive, result_positive) {
result_positive.count(function(err, count){
console.log("Total matches: " + count);
positives[j] = count;
});
counter--;
if (!counter) {
/*
* Last result, now we have all positives.
*
* Add code that need to process the result here.
*
*/
}
}
})(i)
);
}
Namun, jika kita terus melakukan ini, jelas bahwa kita akan berakhir dengan membuat sekelompok variabel sementara dan berakhir dengan kode bersarang yang mengerikan. Tapi ini adalah javascript, kita dapat merangkum logika untuk pola ini dalam suatu fungsi. Inilah implementasi saya dari logika "tunggu-untuk-semua-untuk-lengkap" ini dalam javascript:Mengkoordinasikan eksekusi paralel di node.js
Tetapi karena kita menggunakan node.js, kita dapat menggunakan modul async yang nyaman dari npm:https://npmjs .org/package/async
Dengan async, Anda dapat menulis kode Anda seperti ini:
var queries = [];
// Build up queries:
for (var i=0;i <5; i++) {
queries.push((function(j){
return function(callback) {
collection.find(
{value:1},
{created_on:
{
$gte:startTime + (j*60*1000 - 30*1000),
$lt: startTime + (j*60*1000 + 30*1000)
}
},
function(err_positive, result_positive) {
result_positive.count(function(err, count){
console.log("Total matches: " + count);
positives[j] = count;
callback();
});
}
);
}
})(i));
queries.push((function(j){
return function(callback) {
collection.find(
{value:0},
{created_on:
{
$gte:startTime + (j*60*1000 - 30*1000),
$lt: startTime + (j*60*1000 + 30*1000)
}
},
function(err_negative, result_negative) {
result_negative.count(function(err, count){
console.log("Total matches: " + count);
negatives[j] = count;
callback();
});
}
);
}
})(i));
}
// Now execute the queries:
async.parallel(queries, function(){
// This function executes after all the queries have returned
// So we have access to the completed positives and negatives:
// For example, we can dump the arrays in Firebug:
console.log(positives,negatives);
});