Handling asynchronous database queries in node.js and mongodb
我有这个问题从node.js异步查询mongodb。 这是我的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | var values = []; var positives = new Array(); var negatives = new Array(); var server1 = new mongodb.Server('localhost',27017, {auto_reconnect: true}); var db1 = new mongodb.Db('clicker', server1); db1.open(function(err, db) { if(!err) { db1.collection('feedback', function(err, collection) { for (var i=0;i <5; i++) { collection.find( {value:1}, {created_on: { $gte:startTime + (i*60*1000 - 30*1000), $lt: startTime + (i*60*1000 + 30*1000) } }, function(err_positive, result_positive) { result_positive.count(function(err, count){ console.log("Total matches:" + count); positives[i] = count; }); } ); collection.find( {value:0}, {created_on: { $gte:startTime + (i*60*1000 - 30*1000), $lt: startTime + (i*60*1000 + 30*1000) } }, function(err_negative, result_negative) { result_negative.count(function(err, count){ console.log("Total matches:" + count); negatives[i] = count; }); } ); } }); } else { console.log('Error connecting to the database'); } }); |
实际上,我试图从数据库中获取一些值。 然后我需要操纵这些值。 只是我需要从正计数中减去负计数,然后使用positivecount-negative计数初始化值数组。 现在,因为结果是异步获得的。 我该如何操纵这些值并将它们放在values数组中。
在我进一步解释之前,我想指出您的代码中存在错误:
1 2 3 4 5 6 | 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 } |
经典封口和 循环问题。 请参阅:请解释在循环中使用JavaScript闭包
现在,如何在循环中处理异步函数。 基本思想是,您需要跟踪已完成的异步调用次数,并在最终调用返回后运行代码。 例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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) ); } |
但是,如果我们继续这样做,很明显我们最终会创建一堆临时变量并最终得到可怕的嵌套代码。 但这是javascript,我们可以在函数中封装这个模式的逻辑。 这是我在javascript中实现的"等待完全"逻辑:协调node.js中的并行执行
但是由于我们正在使用node.js,我们可以使用方便的异步模块形式npm:https://npmjs.org/package/async
使用async,您可以像这样编写代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 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); }); |