【问题标题】:Node.JS: Asyncronous Postgres query in for loopNode.JS:for 循环中的异步 Postgres 查询
【发布时间】:2015-04-01 22:33:13
【问题描述】:

我想通过 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 - -

【问题讨论】:

    标签: javascript node.js loops asynchronous


    【解决方案1】:

    查询是异步的。循环不会等待这些查询完成。使用一些流控制库比如'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 = $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));
    });
    

    【讨论】:

    • 谢谢!我只是尝试了一个丑陋的递归函数,但这更简单。
    【解决方案2】:

    您可能希望将async 库用于该工作:本质上它将按顺序运行您的函数。使用命名函数也是一个好习惯,在这种情况下是二阶函数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 接收到一个函数数组时,它会向其回调发送一个结果数组。这就是为什么我们会得到由async 自动构造的result
    • 没有async 也可以这样做,但坦率地说,代码相当复杂,我不建议这样做。

    【讨论】:

      猜你喜欢
      • 2017-12-24
      • 1970-01-01
      • 2018-09-18
      • 2018-10-17
      • 2019-08-24
      • 1970-01-01
      • 1970-01-01
      • 2021-10-16
      • 2015-11-30
      相关资源
      最近更新 更多