在嵌套 for 循环中获取值 - node.js、javascript、redis、Q 库

Getting values within a nest for-loop - node.js, javascript, redis, Q library

我正在尝试从嵌套的 for 循环中提取值。我的循环从 Redis 获取值,我想将这些值添加到名为 "info" 的数组变量中。

重要的一点是 for 循环。

app.get('/query', function(req, res) {

    var info = [];

    redisClient.keys("todo:*", function(err, data) {            

        if (err) return console.log(err);

        for (var i = 0, len = data.length; i < len; i++) {
            var id = data[i];
            var listItem, author, goodness;

            redisClient.hgetall(data[i], function(err, obj) {
                listItem = obj.listItem;
                author = obj.author;
                goodness = {
                    id: id,
                    listItem: listItem,
                    author: author
                }
                info.push(goodness);
                console.log("In here: " + info);

            }); 
            console.log("Out here: " + info);
        }
        console.log("Way out here: " + info);
    }); 
    console.log("WAY THE HECK OUT HERE: " + info);
});

基本上,我希望将变量 "goodness" 中的值推送到名为 "info" 的数组变量中。当我执行代码时,信息数组在这里被填满,

console.log("In here: " + 信息);

但我还没有找到一种方法来提取信息数组,使其具有 redisClient.hgetall() 函数之外的值。我已经尝试了 return 语句但无济于事,尽管作为一名初级程序员,我很有可能没有正确地执行这些语句。

注意:我已尝试从原始答案中获取指导​​,但我一定做错了什么,或者给出的解决方案不够好,或两者兼而有之。我已将 Q 库添加到我的项目中,并试图找到解决方案。这是我当前的代码:

app.get('/query', function(req, res) {

    var redisKeys = Q.nbind(redisClient.keys, redisClient);
    var redisHGetAll = Q.nbind(redisClient.hgetall, redisClient);
    var id, listItem, author;

    var info = [];

    redisKeys('todo:*').then(function (data) {
        console.log("First: " + data);
       var QAll = Q.all(data.map(processKeysFunc(info)));
       console.log("Reading within this: " + data);
       console.log("Next within this: " + QAll);
    }, function (err) { 
        if (err) return console.log(err);
        }).then(function () {
       console.log("Finally: " + data);

    })();

    function processKeysFunc(array) {
        return function (key) {
            console.log("This is the key: " + key);
            return redisHGetall(key).then(function (obj) {
                console.log("This is the obj: " + obj);
                array.push({
                    id: obj.id,
                    listItem: obj.listItem,
                    author: obj.author
                });
            });
        };
    }
});

这就是我在 console.log:

中得到的
First: todo:281f973d-6ffd-403b-a0f4-9e8958caed35,todo:7ed8c557-0f15-4555-9119-
6777e1c952e8,todo:eb8dbee1-92ca-450e-8248-ad78548cd754,todo:712e8d27-bf9b-46f0-bfdd-
c53ef7d14441,todo:301dd91a-2b65-4b87-b129-a5ad569e38e5,todo:720d98b8-bdec-446d-a178-
fb7e264522aa,todo:d200c6cf-2ee5-443b-b7dc-d245c16899c8,todo:8169e9af-0204-42c8-9ddf-
3b00f7161b11

This is the key: todo:281f973d-6ffd-403b-a0f4-9e8958caed35

node.js 一般是非阻塞的,这就是为什么要使用回调。传递给 .hgetall 的回调只会在完全接收到来自 redis 的数据时执行。它周围的其余代码将立即执行,而不是等待来自redis的数据。事实上,由于 .hgetall 调用可能涉及 IO,回调将 always 运行 在代码执行后。

您有几种选择,包括使用 Promises (https://github.com/kriskowal/q)。

我会建议一个解决方案,该解决方案应该可以理解您的代码的当前结构:

app.get('/query', function(req, res) {

    var info = [];
    var completed = 0;

    redisClient.keys("todo:*", function(err, data) {            

        if (err) return console.log(err);

        for (var i = 0, len = data.length; i < len; i++) {
            var id = data[i];
            var listItem, author, goodness;

            redisClient.hgetall(data[i], function(err, obj) {
                completed++;
                if (err) return console.log(err);

                listItem = obj.listItem;
                author = obj.author;
                goodness = {
                    id: id,
                    listItem: listItem,
                    author: author
                }
                info.push(goodness);
                console.log("In here: " + info);

                if (completed === data.length) {
                    // Do something with info here, all work has finished
                }

            }); 
            console.log("Out here: " + info);
        }
        console.log("Way out here: " + info);
    }); 
    console.log("WAY THE HECK OUT HERE: " + info);
});

关键位是新变量 completed,它跟踪返回了多少回调。

不过,我强烈建议改用 promises。类似于:

var Q = require('q');

var redisKeys = Q.nbind(redisClient.keys, redisClient);
var redisHGetall = Q.nbind(redisClient.hgetall, redisClient);

app.get('/query', function(req, res) {
    var info = [];
    redisKeys('todo:*').then(function (data) {
        return Q.all(data.map(processKeysFunc(info));
    }, function (err) { /* handle error */ }).then(function () {
       console.log('Complete info array=%j', info);
       res.setHeader('Content-Type', 'application/json');
       res.end(JSON.stringify(info));
    });
});

function processKeysFunc(array) {
    return function (key) {
        return redisHGetall(key).then(function (obj) {
            var goodness = {
                id: key,
                listItem: obj.listItem,
                author: obj.author
            };
            array.push(goodness);
        });
    }
}

processKeysFunc returns 一个函数,以便您可以干净地传递 info 数组,而无需定义每个内联函数。如果您更喜欢内联,那也可以。