Node.JS: for 循环中的异步 Postgres 查询
Node.JS: Asyncronous Postgres query in for loop
我想通过 for 循环从数据库中查询一些数据。问题是,查询是在循环结束后处理的。
此代码:
ret = [];
first = rows[0];
first.device_firsttime = first.device_lasttime;
first.alerts = [];
for(var i = 0; i < 5; i++)
{
console.log("!"+i);
(function(i) {
query("SELECT EXTRACT('epoch' FROM alert_time)::integer alert_time, alert_id, alert_lat, alert_lon, alert_str, alert_cc, alert_distance FROM blitz_device_former_alerts WHERE alert_locid = ", [first.device_locid], function(error_a,rows_a,result_a)
{
console.log(i+"!");
ret.push(i);
});
})(i);
}
console.log("-END---"+JSON.stringify(ret));
ret.push(first);
res.end(JSON.stringify(ret));
正在将此写入控制台:
!0
!1
!2
!3
!4
-END---[]
POST /userlogs 200 140.110 ms - -
0!
1!
2!
3!
4!
正确的输出应该是
!0
0!
!1
1!
!2
2!
!3
3!
!4
4!
-END---[0,1,2,3,4]
POST /userlogs 200 xxx.xxx ms - -
查询是异步的。循环不会等待这些查询完成。使用一些流程控制库更容易,例如 'async'.
var async = require('async');
async.eachSeries([0, 1, 2, 3, 4], function(i, callback) {
console.log("!"+i);
query("SELECT EXTRACT('epoch' FROM alert_time)::integer alert_time, alert_id, alert_lat, alert_lon, alert_str, alert_cc, alert_distance FROM blitz_device_former_alerts WHERE alert_locid = ", [first.device_locid], function(error_a,rows_a,result_a) {
console.log(i+"!");
ret.push(i);
callback(null); // null -> no error
});
}, function(err) {
console.log("-END---"+JSON.stringify(ret));
ret.push(first);
res.end(JSON.stringify(ret));
});
您可能希望使用 async 库来完成该工作:本质上它将 运行 按顺序执行您的函数。使用命名函数也是一个好习惯,在本例中是二阶函数 getExtractor()
:一个函数 returns 另一个函数,可由 async
使用。 async
喜欢有接受回调的函数,也就是每次执行的结果都加进去的地方。
代码应该是这样的:
var async = require('async');
first = rows[0];
first.device_firsttime = first.device_lasttime;
first.alerts = [];
var tasks = [];
for(var i = 0; i < 5; i++)
{
tasks.push(getExtractor(i));
}
async.series(function(result) {
console.log("-END---"+JSON.stringify(result));
result.push(first);
res.end(JSON.stringify(result));
});
function getExtractor(i) {
return function(callback) {
console.log("!"+i);
query("SELECT EXTRACT('epoch' FROM alert_time)::integer alert_time, alert_id, alert_lat, alert_lon, alert_str, alert_cc, alert_distance FROM blitz_device_former_alerts WHERE alert_locid = ", [first.device_locid], function(error_a,rows_a,result_a)
{
console.log(i+"!");
return callback(null, i);
});
});
}
一些注意事项:
- 推送到
tasks
数组的每个函数都接受 function(error, result)
形式的回调。第一个参数是一个可选错误。
- 为了简单起见,我没有处理代码中的错误,但这样做很重要。
- 如果出于任何原因你想 运行 所有功能并行,你可以只使用
async.parallel()
.
- 在传递给
async.series()
. 的回调中执行最后一点(当收集完所有片段时)
- 当
async
收到一组函数时,它会向其回调发送一组结果。这就是为什么我们得到 async
. 自动构造的 result
- 没有
async
你也可以这样做,但坦率地说,代码非常复杂,我不推荐它。
我想通过 for 循环从数据库中查询一些数据。问题是,查询是在循环结束后处理的。
此代码:
ret = [];
first = rows[0];
first.device_firsttime = first.device_lasttime;
first.alerts = [];
for(var i = 0; i < 5; i++)
{
console.log("!"+i);
(function(i) {
query("SELECT EXTRACT('epoch' FROM alert_time)::integer alert_time, alert_id, alert_lat, alert_lon, alert_str, alert_cc, alert_distance FROM blitz_device_former_alerts WHERE alert_locid = ", [first.device_locid], function(error_a,rows_a,result_a)
{
console.log(i+"!");
ret.push(i);
});
})(i);
}
console.log("-END---"+JSON.stringify(ret));
ret.push(first);
res.end(JSON.stringify(ret));
正在将此写入控制台:
!0
!1
!2
!3
!4
-END---[]
POST /userlogs 200 140.110 ms - -
0!
1!
2!
3!
4!
正确的输出应该是
!0
0!
!1
1!
!2
2!
!3
3!
!4
4!
-END---[0,1,2,3,4]
POST /userlogs 200 xxx.xxx ms - -
查询是异步的。循环不会等待这些查询完成。使用一些流程控制库更容易,例如 'async'.
var async = require('async');
async.eachSeries([0, 1, 2, 3, 4], function(i, callback) {
console.log("!"+i);
query("SELECT EXTRACT('epoch' FROM alert_time)::integer alert_time, alert_id, alert_lat, alert_lon, alert_str, alert_cc, alert_distance FROM blitz_device_former_alerts WHERE alert_locid = ", [first.device_locid], function(error_a,rows_a,result_a) {
console.log(i+"!");
ret.push(i);
callback(null); // null -> no error
});
}, function(err) {
console.log("-END---"+JSON.stringify(ret));
ret.push(first);
res.end(JSON.stringify(ret));
});
您可能希望使用 async 库来完成该工作:本质上它将 运行 按顺序执行您的函数。使用命名函数也是一个好习惯,在本例中是二阶函数 getExtractor()
:一个函数 returns 另一个函数,可由 async
使用。 async
喜欢有接受回调的函数,也就是每次执行的结果都加进去的地方。
代码应该是这样的:
var async = require('async');
first = rows[0];
first.device_firsttime = first.device_lasttime;
first.alerts = [];
var tasks = [];
for(var i = 0; i < 5; i++)
{
tasks.push(getExtractor(i));
}
async.series(function(result) {
console.log("-END---"+JSON.stringify(result));
result.push(first);
res.end(JSON.stringify(result));
});
function getExtractor(i) {
return function(callback) {
console.log("!"+i);
query("SELECT EXTRACT('epoch' FROM alert_time)::integer alert_time, alert_id, alert_lat, alert_lon, alert_str, alert_cc, alert_distance FROM blitz_device_former_alerts WHERE alert_locid = ", [first.device_locid], function(error_a,rows_a,result_a)
{
console.log(i+"!");
return callback(null, i);
});
});
}
一些注意事项:
- 推送到
tasks
数组的每个函数都接受function(error, result)
形式的回调。第一个参数是一个可选错误。 - 为了简单起见,我没有处理代码中的错误,但这样做很重要。
- 如果出于任何原因你想 运行 所有功能并行,你可以只使用
async.parallel()
. - 在传递给
async.series()
. 的回调中执行最后一点(当收集完所有片段时)
- 当
async
收到一组函数时,它会向其回调发送一组结果。这就是为什么我们得到async
. 自动构造的 - 没有
async
你也可以这样做,但坦率地说,代码非常复杂,我不推荐它。
result