0

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

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

不仅为这两个请求调用了第二个函数,而且似乎在客户端的查询队列完成运行之前调用了排水代码......然而第二个查询仍然运行得很好,即使client.end()代码表面上杀死了调用事件后的客户端。

几个小时以来,我一直在为此烦恼。我尝试在我的示例数组中进行硬编码(从而删除了 for 循环),并且我的代码按预期工作,这让我相信我的循环存在一些我没有看到的问题。

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

4

3 回答 3

1

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

我正在尝试使用 nodejs 打开 10 个 websocket 连接,但不知何故我的循环不起作用

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

于 2013-11-18T10:26:23.033 回答
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以便内部回调可以正确评估它。

于 2013-11-18T12:14:32.323 回答
0

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

于 2014-12-16T10:16:06.440 回答