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.