Trước khi giải thích thêm, tôi muốn lưu ý rằng có một lỗi trong mã của bạn:
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
}
Sự cố về vòng lặp và đóng cửa cổ điển. Xem: Vui lòng giải thích việc sử dụng các đóng JavaScript trong các vòng lặp
Bây giờ, làm thế nào để xử lý các hàm không đồng bộ trong vòng lặp. Ý tưởng cơ bản là bạn cần theo dõi có bao nhiêu cuộc gọi không đồng bộ đã hoàn thành và chạy mã của bạn khi cuộc gọi cuối cùng trả về. Ví dụ:
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)
);
}
Tuy nhiên, nếu chúng ta tiếp tục làm điều này, rõ ràng là chúng ta sẽ tạo ra một loạt các biến tạm thời và kết thúc với mã lồng nhau khủng khiếp. Nhưng đây là javascript, chúng ta có thể đóng gói logic cho mẫu này trong một hàm. Đây là cách tôi triển khai logic "đợi-cho-tất cả-để hoàn thành" này trong javascript: Điều phối thực thi song song trong node.js
Nhưng vì chúng tôi đang sử dụng node.js, chúng tôi có thể sử dụng biểu mẫu mô-đun không đồng bộ thuận tiện npm: https:// npmjs .org / package / async
Với không đồng bộ, bạn có thể viết mã của mình như sau:
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);
});