1

我正在构建一个小 Node.js 应用程序,我需要做的一件事是获取 Redis 数据存储区中的所有数据并将其显示在此特定页面上。到目前为止,我的代码如下所示:

exports.view = function (req, res) {
    rclient.keys('*', function (err, reply) {
        var data = {};

        // Get the value for each key
        for (var i = 0; i < reply.length; i++) {
            rclient.GET(reply[i], function (err, value) {
                data[reply[i]] = value;
            });
        }

        res.render('view', {title: 'Datastore', data: data});
    });
};

我在这里至少有两个问题。一:由于 Node.js 的异步特性,当我将 data 变量传递给我的渲染函数时,它是空的。避免这种情况的正确方法是什么?

二:变量 i 不等于我的回调中的预期值,因为循环已经增加,并且由于作用域,在调用第一次迭代的回调时 i 等于 1(它应该是 0)。

我对 Node.js 很陌生,所以我确定我做错了什么。

4

2 回答 2

1

考虑以下函数:

exports.view = function (req, res) {
  rclient.keys('*', function (err, reply) {
    var data = {};
    var count = reply.length;
    reply.forEach( function(key) {
      rclient.get( key, function (err, value) {
        data[key] = value;
        --count;
        if (count <= 0) {
          res.render('view', {title: 'Datastore', data: data});
        }
      });
    });
  });
};

要解决您的第一个问题,您需要在收到所有结果后调用内部回调中的最后一条语句。您可以通过计算预期项目来确保这一点,并仅在处理完最后一个项目后调用渲染语句。

要解决您的第二个问题,您可以使用引入另一个功能范围的 forEach 语句。在 Javascript 中,闭包的范围是在函数级别定义的,而不是在块级别。用 forEach 替换 for 循环是解决此问题的一种优雅方法。

最后一点:在实际应用程序中使用 KEYS 命令是一种非常糟糕的做法。KEYS 仅用作调试工具。

于 2013-05-30T19:47:38.073 回答
0

我最终建立在 Didier 的响应之上,并使用了 async.js

exports.view = function (req, res) {
    // Get all of the key information for the given key
    var getKeyInfo = function (key, callback) {
        async.parallel([
            rclient.GET.bind(rclient, [key]),
            rclient.TTL.bind(rclient, [key]),
            rclient.TYPE.bind(rclient, [key])
        ], callback);
    }

    // Fetch all keys in our data store
    rclient.KEYS('*', function (err, keys) {
        var asyncCallbacks = {};

        // Build an array of callbacks for our async operation
        for (var i = 0; i < keys.length; i++) {
            asyncCallbacks[keys[i]] = async.apply(getKeyInfo, keys[i]);
        }

        // Asynchronously get the data for each key in the data store
        async.parallel(asyncCallbacks, function (err, results) {
            res.render('view', {title: 'Datastore', data: results});
        });
    });
};
于 2013-05-31T14:51:12.377 回答