2 Stimmen

for-Schleife über ereignisgesteuerten Code?

In einem Redis-Datenspeicher habe ich eine Liste von Schlüsseln, ich möchte über diese Liste von Schlüsseln iterieren und diese Werte von Redis erhalten. Der Haken ist, dass ich eine ereignisgesteuerte Sprache verwende, nämlich Javascript über node.js

Wenn javascript prozedural wäre, könnte ich dies tun

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);
}

Aber ich kann deshalb nicht ich dies tun?

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()
    });
};

Das scheint falsch zu sein, denn anstatt alle Anfragen auf einmal auszuführen und dann Rückrufe in die Liste einfügen zu lassen, erzwinge ich eine sequentielle Aufrufsequenz. Was passiert, wenn es 1000e von Schlüsseln gibt?

Kann ich das irgendwie machen?

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);
    });
};

3voto

T.J. Crowder Punkte 948310

Wie kann man blockieren, bis man fertig ist?

Das geht nicht, nicht wenn die Anrufe asynchron sind. Sie müssen Ihre getAll mit der Erwartung, dass es asynchron abgeschlossen wird, und dann ein bisschen umschreiben.

Ich bin nicht vertraut mit den Redis-Aufrufen, die Sie machen, aber das grundlegende Muster ist:

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);
            }
        }
    });
}

Die Aufschlüsselung:

  1. doBigThing (Ihr getAll ) genannt wird.
  2. Es macht den "get the list"-Aufruf und übergibt die Funktion, die als Callback verwendet werden soll, wenn wir die Liste oder das Listenhandle oder was auch immer haben.
  3. Dieser Rückruf definiert eine Funktion, receivedNextEntry und ruft die Funktion "get the next entry" mit den Informationen auf, die zum Abrufen des Eintrags verwendet werden, und übergibt diese als Callback.
  4. receivedNextEntry speichert den erhaltenen Eintrag und löst, wenn er fertig ist, den Haupt-Callback "all done" aus; wenn nicht, wird die nächste Anfrage gestellt.

Leider kann ich Ihnen keine redis-spezifische Antwort geben, aber ich piense en sind die Zuordnungen:

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

...aber was sind die Parameter, die Sie mit redis.lrange y redis.hgetall Ich fürchte, ich weiß es nicht.

1voto

b_erb Punkte 20272

Deklarieren Sie eine Objektvariable, bevor Sie Ihre Aufrufe innerhalb der for-Schleife absetzen. Jeder Aufruf kann dann sein Ergebnis in das Objekt einfügen.

Sie brauchen dann Code, um zu warten, bis alle Anrufe erledigt sind. Dies könnte Ihnen helfen: https://gist.github.com/464179

Ejemplo:

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();
        });
    }
}

Bitte beachten Sie, dass call() sollte Ihre asynchrone Datenbankfunktion sein, die den Callback auf das Ergebnis ausführt.

1voto

Caolan Punkte 3889

Wenn Sie derartige Muster häufig verwenden müssen, sollten Sie vielleicht die async.js-Bibliothek . Mit async.js könnten Sie etwas wie dieses schreiben:

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

Das bedeutet im Grunde "hgetall für jedes Element in 'reply' aufrufen, dann alle Ergebnisse zusammenfassen und an den Callback übergeben".

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X