如何在循环内完成异步函数后调用函数?

时间:2014-04-01 14:42:52

标签: javascript node.js callback redis promise

我在NodeJS中有一个forEach循环,迭代一系列键,然后从Redis异步检索其值。一旦循环和检索完成,我想将该数据集作为响应返回。

我目前的问题是因为数据检索是异常的,我的数组在发送响应时不会被填充。

如何在forEach循环中使用promises或callback来确保响应是随数据一起发送的?

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));
    })

2 个答案:

答案 0 :(得分:11)

我在这里使用Bluebird promises。注意代码的意图是如何清晰的,没有嵌套。

首先,让promisify hgetall调用和客户端 -

var client = Promise.promisifyAll(client);

现在,让我们使用promises .then编写代码,而不是使用.map编写节点回调和聚合。 .then的作用是表示异步操作已完成。 .map获取一系列内容并将它们全部映射到异步操作,就像您的hgetall调用一样。

请注意Bluebird如何(默认情况下)为promisifed方法添加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
    });
};

答案 1 :(得分:1)

不需要lib。很简单,它只是一个异步循环。省略错误处理。如果您需要执行并行异步循环,请使用计数器。

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);
});