Node.JS:异步 Postgres 查询 in for 循环

Node.JS: Asyncronous Postgres query in for loop

本文关键字:in for 循环 查询 Postgres JS 异步 Node      更新时间:2023-09-26

我想从数据库中查询一些数据,从一个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 = $1", [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 - -

查询是异步的。 循环不会等待这些查询完成。 使用一些流控制库(如"异步")更容易。

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 = $1", [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));
});

您可能希望为该作业使用异步库:本质上,它将按顺序运行您的函数。使用命名函数也是一种很好的做法,在这种情况下是二阶函数getExtractor():返回另一个函数的函数,可由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 = $1", [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收到函数数组时,它会向其回调发送结果数组。这就是为什么我们得到resultasync .
  • 你可以在没有async的情况下做同样的事情,但坦率地说,代码非常复杂,我不推荐它。