2

redis データストアにはキーのリストがあり、そのキーのリストを反復処理して、redis からそれらの値を取得したいと考えています。キャッチは、イベント駆動型言語、node.js経由のjavascriptを使用していることです

JavaScriptが手続き型である場合、私はこれを行うことができます

function getAll(callback) {
    var list = redis.lrange(lrange('mykey', 0, -1);
    for ( var i = 0; i < list.length; i+= 1 ) {
        list[i] = redis.hgetall(list[i]);
    }
    callback(list);
}

しかし、私はできないので.. 私はこれをしますか?

function getAll(callback) {
    redis.lrange('mykey', 0, -1, function(err, reply) {
        // convert reply into messages
        var list = [];
        var index = -1;
        var recurse = function() {
            if ( index == reply.length ) {
                callback(list);
            } else {
                redis.hgetall(reply[i], function(err, reply) {
                    list.push(reply);
                    index += 1;
                    recurse();
                });
            }
        };
        recurse()
    });
};

すべてのリクエストを一度に実行してからコールバックをリストに挿入する代わりに、順次呼び出しシーケンスを強制しているため、これは間違っています。何千ものキーがあるとどうなりますか?

どうにかしてこれを行うことができますか?

function getAll(callback) {
    redis.lrange('mykey', 0, -1, function(err, reply) {

        // convert reply into messages
        var list = [];
        var insert = function(err, reply) {
            list.push(reply);
        };
        for ( var i = 0; i < reply.length; i += 1 ) {
            redis.hgetall(reply[i], insert);
        }

        ??? how to block until finished ??? 
        callback(list);
    });
};
4

3 に答える 3

3

??? 完了するまでブロックする方法???

呼び出しが非同期の場合はできません。getAll非同期で完了することを期待して定義し、少し再キャストする必要があります。

私はあなたが行っている redis 呼び出しに慣れていませんが、基本的なパターンは次のとおりです。

function doTheBigThing(param, callbackWhenDone) {
    asyncCallToGetList(param, function(result) {
        var list = [];

        asyncCallToGetNextEntry(result.thingy, receivedNextEntry);

        function receivedNextEntry(nextResult) {
            if (nextResult.meansWeAreDone) {
                callback(list);
            }
            else {
                list.push(nextResult.info);
                asyncCallToGetNextEntry(result.thingy, receivedNextEntry);
            }
        }
    });
}

それを分解する:

  1. doBigThing(あなたのgetAll) が呼び出されます。
  2. 「リストを取得」呼び出しを行い、リストまたはリスト ハンドルなどがある場合にコールバックとして使用する関数を渡します。
  3. そのコールバックは関数 を定義し、receivedNextEntryエントリを取得するために使用される情報を使用して「次のエントリを取得する」関数を呼び出し、それをコールバックとして渡します。
  4. receivedNextEntry取得したエントリを保存し、完了したら、メインの「すべて完了」コールバックを起動します。そうでない場合は、次のリクエストを発行します。

redis 固有の回答を提供できなくて申し訳ありませんが、マッピングは次のとおりだと思います。

  • doBigThing=getAll
  • asyncCallToGetList=redis.lrange
  • asyncCallToGetNextEntry=redis.hgetall

...しかし、どのパラメーターを使用しているのか、残念ながらredis.lrangeわかりredis.hgetallません。

于 2011-01-02T19:22:46.583 に答える
1

このようなパターンを頻繁に使用する必要がある場合は、async.js ライブラリを試すことに興味があるかもしれません。async.js を使用すると、次のように記述できます。

function getAll(callback) {
    redis.lrange('mykey', 0, -1, function(err, reply) {
        async.concat(reply, redis.hgetall, callback);
    });
};

これは基本的に、「「返信」の各項目で hgetall を呼び出し、すべての結果を連結してコールバックに渡す」ことを意味します。

于 2011-01-04T13:42:17.930 に答える
1

for ループ内で呼び出しをディスパッチする前に、オブジェクト変数を宣言します。各呼び出しは、その結果をオブジェクトに追加できます。

次に、すべての呼び出しが完了するまで待機するコードが必要です。これはあなたを助けるかもしれません: https://gist.github.com/464179

例:

function getAll(callback) {

    var results = [];

    var b = new Barrier(2, function() {
        // all complete callback
        callback();
        }, function() {
        // Aborted callback, not used here
    });

    var list = redis.lrange(lrange('mykey', 0, -1);
    for ( var i = 0; i < list.length; i+= 1 ) {
        //dispatch your call
        call(function(foo){
            results.push(foo);
            b.submit();
        });
    }
}

call()結果に対してコールバックを実行する非同期データベース関数である必要があることに注意してください。

于 2011-01-02T19:24:56.043 に答える