使用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循环),并且我的代码按预期工作,这让我相信我的循环中存在一些我没有看到的问题。
对于为什么会发生这种情况的任何想法都将不胜感激。
答案 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