循环内的异步函数完成后如何调用函数?
Posted
技术标签:
【中文标题】循环内的异步函数完成后如何调用函数?【英文标题】:How to call function after completion of async functions inside loop? 【发布时间】:2014-05-12 10:11:51 【问题描述】:我在 NodeJS 中有一个 forEach 循环,遍历一系列键,然后从 Redis 异步检索这些键的值。循环和检索完成后,我想将该数据集作为响应返回。
我目前的问题是因为数据检索是异步的,发送响应时我的数组没有填充。
如何在我的 forEach 循环中使用 Promise 或回调来确保响应与数据一起发送?
exports.awesomeThings = function(req, res)
var things = [];
client.lrange("awesomeThings", 0, -1, function(err, awesomeThings)
awesomeThings.forEach(function(awesomeThing)
client.hgetall("awesomething:"+awesomeThing, function(err, thing)
things.push(thing);
)
)
console.log(things);
return res.send(JSON.stringify(things));
)
【问题讨论】:
这个问题有很多QA。有些列在此页面的右侧。 现在,我建议使用 Promise 库。 Here's an introduction @dystroy 您应该考虑为该问题添加一个承诺答案。现在的比较丑。此外,还有一些异步信号量。 【参考方案1】:我在这里使用Bluebird promises。请注意代码的意图是多么清晰,并且没有嵌套。
首先,让我们promisify hgetall 调用和客户端 -
var client = Promise.promisifyAll(client);
现在,让我们编写带有 Promise 的代码,.then
,而不是使用 .map
的节点回调和聚合。 .then
所做的是表示异步操作已完成。 .map
获取一系列事物并将它们全部映射到异步操作,就像您的 hgetall 调用一样。
注意 Bluebird 如何(默认情况下)向承诺的方法添加 Async
后缀。
exports.awesomeThings = function(req, res)
// make initial request, map the array - each element to a result
return client.lrangeAsync("awesomeThings", 0, -1).map(function(awesomeThing)
return client.hgetallAsync("awesomething:" + awesomeThing);
).then(function(things) // all results ready
console.log(things); // log them
res.send(JSON.stringify(things)); // send them
return things; // so you can use from outside
);
;
【讨论】:
谢谢,这是完美的。我知道承诺会是解决这个问题的方法,但是我发现的很多解决方案(自从发布这个问题以来)都非常……冗长。 很高兴我能帮上忙。 Promise 是一个非常强大的抽象,并且可以很好地简化代码。它们还内置了可调试性——如果上面的任何代码有错误——你会知道 Bluebird 的承诺。它们链接得很好,它们组合得很好,并且包含您实际需要的并发原语。从 EcmaScript 6 开始,它们也是 javascript 的一部分——下一个标准,因此可以公平地假设使用它们的代码非常兼容未来。【参考方案2】:不需要库。很简单,它只是一个异步循环。省略了错误处理。如果您需要执行并行异步循环,请使用计数器。
exports.awesomeThings = function(req, res)
client.lrange("awesomeThings", 0, -1, function(err, awesomeThings)
var len = awesomeThings.length;
var things = [];
(function again (i)
if (i === len)
//End
res.send(JSON.stringify(things));
else
client.hgetall("awesomething:"+awesomeThings[i], function(err, thing)
things.push(thing);
//Next item
again (i + 1);
)
)(0);
);
【讨论】:
以上是关于循环内的异步函数完成后如何调用函数?的主要内容,如果未能解决你的问题,请参考以下文章