【问题标题】: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 您应该考虑为该问题添加一个承诺答案。现在的比较丑。此外,还有一些异步信号量。

标签: javascript node.js callback redis promise


【解决方案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);
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-14
    • 2020-11-14
    • 1970-01-01
    • 2017-07-27
    • 1970-01-01
    相关资源
    最近更新 更多