Jag skulle gå den väg du föreslår i din fråga och bifoga en anpassad återuppringning till din hämtningsfunktion:
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
});
Det är förmodligen den mest effektiva metoden; alternativt kan du lita på en gammal skola while
loop tills data är klar:
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);
}
});
Vi använder process.nextTick
istället för en faktisk while
för att se till att andra förfrågningar inte blockeras under tiden; På grund av Javascripts enkeltrådade natur är detta det föredragna sättet. Jag slänger in det här för fullständighetens skull, men den förstnämnda metoden är effektivare och passar bättre med node.js, så kör på det om inte en större omskrivning är inblandad.
Det är ingenting värt att båda fallen förlitar sig på asynkrona återuppringningar, vilket innebär att all kod utanför den fortfarande kan köras innan andra är klara. Till exempel genom att använda vårt första utdrag:
function getStudentsData(callback) {
//[...]
}
getStudentsData(function(dataList) {
//[...]
});
console.log("hello world");
Den sista console.log kommer nästan garanterat att köras innan vår callback skickas till getStudentsData avfyras. Jobba runt? Design för det, det är bara hur node.js fungerar. I vårt fall ovan är det enkelt, vi skulle bara kalla console.log endast i vår callback skickas till getStudentsData och inte utanför den. Andra scenarier kräver lösningar som avviker lite mer från traditionell procedurkodning, men när du väl har bestämt dig för det kommer du att upptäcka att vara händelsestyrd och att icke-blockerande faktiskt är en ganska kraftfull funktion.