1

私は小さな Node.js アプリを作成しています。実行する必要があることの 1 つは、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});
    });
};

ここには少なくとも 2 つの問題があります。1: Node.js の非同期性のため、データ変数をレンダー関数に渡すと空になります。これを回避する適切な方法は何ですか?

2: 変数 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});
        }
      });
    });
  });
};

最初の問題を解決するには、すべての結果を受け取ったら、内側のコールバックで最後のステートメントを呼び出す必要があります。予想されるアイテムを数えることでそれを確認し、最後のアイテムが処理された後にのみ render ステートメントを呼び出すことができます。

2 番目の問題を解決するには、別の機能スコープを導入する forEach ステートメントを使用できます。Javascript では、クロージャのスコープはブロック レベルではなく、関数レベルで定義されます。for ループを forEach に置き換えることは、この問題を回避するエレガントな方法です。

最後のポイント: 実際のアプリケーションで KEYS コマンドを使用することは、非常に悪い習慣です。KEYS は、デバッグ機能としてのみ使用することを意図しています。

于 2013-05-30T19:47:38.073 に答える