在Node.js中处理异步循环的最佳模式

Mat*_* S. 6 javascript redis node.js

我是Node的新手,并试图确保我为JSON驱动的Web应用程序使用理智的设计.

我有一堆数据存储在Redis中,我正在通过节点检索它,将结果流出来,因为它们来自Redis.这是我正在做的一个很好的例子:

app.get("/facility", function(req, res) {
    rc.keys("FACILITY*", function(err, replies) {
        res.write("[");
        replies.forEach(function (reply, i) {
            rc.get(reply, function(err, reply) {
                res.write(reply);
                if (i == replies.length-1) {
                    res.write("]");
                    res.end();
                }
                else
                    res.write(",");
            });
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

基本上我从Redis获取一组密钥然后请求每个密钥,将结果流式传输到半手动创建的JSON(Redis中的字符串已经是JSON).现在这很好用,但我不禁想到i == replies.length-1有点乱?

我可以用Redis中的mget完成所有这些,但这并不是我想要得到它的重点; 这是如何最好地处理与forEach的异步循环,流式输出和优雅地关闭与res.end的连接与循环完成.

这是最好的方式,还是我可以遵循更优雅的模式?

s4y*_*s4y 6

上面的代码可能无法达到预期效果.你.get()按顺序踢了每个,但是它们可能不会按顺序回调 - 所以结果可以按任何顺序流出.如果要流式传输结果而不是将其收集到内存中,则需要.get()按顺序进行.

我认为caolan的异步库使这很容易.这是您可以使用它来按顺序获取每个项目的一种方法(警告,未经测试):

app.get("/facility", function(req, res) {
    rc.keys("FACILITY*", function(err, replies) {
        var i = 0;
        res.write("[");
        async.forEachSeries(replies, function(reply, callback){
            rc.get(reply, function(err, reply) {
                if (err){
                    callback(err);
                    return;
                }
                res.write(reply);
                if (i < replies.length) {
                    res.write(",");
                }
                i++;
                callback();
            });
        }, function(err){
            if (err) {
                // Handle an error
            } else {
                res.end(']');
            }
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

如果您不关心订单,请async.forEach()改用.

如果您不介意收集结果并希望它们按顺序返回,您可以async.map()像这样使用(警告,也未经测试):

app.get("/facility", function(req, res) {
    rc.keys("FACILITY*", function(err, replies) {
        async.map(replies, rc.get.bind(rc), function(err, replies){
            if (err) {
                // Handle an error
            } else {
                res.end('[' + replies.join(',') + ']');
            }
        });
    });
});
Run Code Online (Sandbox Code Playgroud)