Node中PostgreSQL的异步数据库查询无法正常工作

时间:2013-11-18 01:59:21

标签: node.js postgresql node-postgres

使用Node.js和node-postgres module与数据库通信,我正在尝试编写一个接受查询和回调数组的函数,并使用相同的数据库连接异步执行它们。该函数接受一个二维数组,并调用它如下所示:

perform_queries_async([
  ['SELECT COUNT(id) as count FROM ideas', function(result) {
    console.log("FUNCTION 1");
  }],
  ["INSERT INTO ideas (name) VALUES ('test')", function(result) {
    console.log("FUNCTION 2");
  }]
]);

该函数遍历数组,为每个子数组创建一个查询,如下所示:

function perform_queries_async(queries) {
  var client = new pg.Client(process.env.DATABASE_URL);

  for(var i=0; i<queries.length; i++) {
    var q = queries[i];

    client.query(q[0], function(err, result) {
      if(err) {
        console.log(err);
      } else {
        q[1](result);
      }
    });
  }

  client.on('drain', function() {
    console.log("drained");
    client.end();
  });

  client.connect();
}

当我运行上面的代码时,我希望看到这样的输出:

FUNCTION 1
FUNCTION 2
drained

然而,输出奇怪地显示如下:

FUNCTION 2
drained
FUNCTION 2

不仅第二个函数被调用了两个请求,看起来似乎在客户端的查询队列运行完毕之前调用了耗尽代码......但是第二个查询仍然运行完全正常,即使{ {1}}代码在调用事件后表面上杀死了客户端。

我已经把头发弄了几个小时。我在我的示例数组中尝试了硬编码(因此删除了for循环),并且我的代码按预期工作,这让我相信我的循环中存在一些我没有看到的问题。

对于为什么会发生这种情况的任何想法都将不胜感激。

3 个答案:

答案 0 :(得分:1)

着名的Javascript闭包/循环陷阱的受害者。在这里查看我的(和其他)答案:

I am trying to open 10 websocket connections with nodejs, but somehow my loop doesnt work

基本上,在执行回调时,q被设置为输入数组的最后一个元素。解决它的方法是动态生成闭包。

答案 1 :(得分:1)

在现代JavaScript中正确捕获闭包中q变量值的最简单方法是使用forEach

queries.forEach(function(q) {
    client.query(q[0], function(err, result) {
      if(err) {
        console.log(err);
      } else {
        q[1](result);
      }
    });
 });

如果未捕获该值,则代码将反映q在包含函数的上下文中作为稍后执行的回调函数的最后一个值。

forEach,通过使用回调函数隔离并捕获q的值,以便内部回调可以正确评估它。

答案 2 :(得分:0)

使用异步模块执行此操作会很好。它还可以帮助您重用代码。并将使代码更具可读性。我只是喜欢异步模块提供的自动功能 参考:https://github.com/caolan/async