Redis
 sql >> Base de données >  >> NoSQL >> Redis

Node.js &Redis ; Attendre qu'une boucle se termine

Je suivrais la voie que vous suggérez dans votre question et j'attacherais un rappel personnalisé à votre fonction de récupération :

function getStudentsData(callback) {
    var setList = [];
    var dataList = [];

    redisClient.smembers("student_setList", function(err,result) {
        setList = result; //id's of students

        for(var i = 0; i < setList.length; i++) {
            redisClient.get(setList[i], function(err, result) {
                if(err) {
                    console.log("Error: "+err);
                } else {
                    tempObject = JSON.parse(result);
                    if(tempObject.name != null) {
                        dataList.push(tempObject);
                    }
                }
            });     
        }

        if(dataList.length == setList.length) {
            if(typeof callback == "function") {
                callback(dataList);
            }
            console.log("getStudentsData: done");
        } else {
            console.log("getStudentsData: length mistmach");
        }

    });
}

getStudentsData(function(dataList) {
    console.log("Goes here after checking every single object");
    console.log(dataList.length);
    //More code here
});

C'est probablement la méthode la plus efficace; alternativement, vous pouvez compter sur une vieille école while boucle jusqu'à ce que les données soient prêtes :

var finalList = [];
var list = [0];

redisClient.smembers("student_list", function(err,result) {
    list = result; //id's of students
    var possibleStudents = [];

    for(var i = 0; i < list.length; i++) {
        redisClient.get(list[i], function(err, result) {
            if(err) {
                console.log("Error: "+err);
            } else {
                tempObject = JSON.parse(result);
                if(tempObject.name != null) {
                    finalList.push(tempObject);
                }
            }
        });     
    }
});


process.nextTick(function() {
    if(finalList.length == list.length) {
        //Done
        console.log("Goes here after checking every single object");
        console.log(dataList.length);
        //More code here
    } else {
        //Not done, keep looping
        process.nextTick(arguments.callee);
    }
});

Nous utilisons process.nextTick au lieu d'un réel while pour s'assurer que d'autres demandes ne sont pas bloquées entre-temps ; en raison de la nature à thread unique de Javascript, c'est la méthode préférée. J'ajoute cela par souci d'exhaustivité, mais la première méthode est plus efficace et convient mieux à node.js, alors allez-y à moins qu'une réécriture majeure ne soit impliquée.

Cela ne vaut rien que les deux cas reposent sur des rappels asynchrones, ce qui signifie que tout code en dehors de celui-ci peut toujours potentiellement s'exécuter avant que les autres ne soient terminés. Par exemple, en utilisant notre premier extrait :

function getStudentsData(callback) {
    //[...]
}

getStudentsData(function(dataList) {
    //[...]
});

console.log("hello world");

Ce dernier console.log est presque assuré de s'exécuter avant que notre rappel passé à getStudentsData ne soit déclenché. Solution de contournement? Concevoir pour cela, c'est juste comment fonctionne node.js. Dans notre cas ci-dessus, c'est facile, nous appellerions simplement console.log uniquement dans notre rappel passé à getStudentsData et non à l'extérieur. D'autres scénarios nécessitent des solutions qui s'écartent un peu plus du codage procédural traditionnel, mais une fois que vous aurez compris, vous constaterez qu'être piloté par les événements et non bloquant est en fait une fonctionnalité assez puissante.