для циклического кода, управляемого событиями?

В хранилище данных Redis у меня есть список ключей, я хочу перебрать этот список ключей и получить эти значения из Redis. Подвох в том, что я использую язык, управляемый событиями, javascript через node.js

Если бы 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()
    });
};

Это кажется неправильным, потому что вместо того, чтобы выполнять все запросы одновременно, а затем позволять обратным вызовам вставляться в список, я форсирую последовательную последовательность вызовов. Что произойдет, если есть 1000 ключей?

Могу ли я сделать это как-нибудь?

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

person Daniel    schedule 02.01.2011    source источник
comment
Оба эти ответа великолепны, суть Барьера помогла мне.   -  person Daniel    schedule 03.01.2011


Ответы (3)


Объявите объектную переменную перед отправкой вызовов в цикле 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() должна быть вашей асинхронной функцией базы данных, которая выполняет обратный вызов для результата.

person b_erb    schedule 02.01.2011

??? как заблокировать пока не закончу???

Вы не можете, если вызовы, которые вы делаете, асинхронны. Вы должны определить свой 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, боюсь, я не знаю.

person T.J. Crowder    schedule 02.01.2011
comment
Благодарю вас! Это определенно помогает! - person Daniel; 03.01.2011