Pójdę drogą, którą sugerujesz w swoim pytaniu, i dołączę niestandardowe wywołanie zwrotne do funkcji pobierania:
Funkcjafunction 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
});
To prawdopodobnie najskuteczniejsza metoda; alternatywnie możesz polegać na starej szkole while
pętla, aż dane będą gotowe:
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);
}
});
Używamy process.nextTick
zamiast rzeczywistego while
aby upewnić się, że inne żądania nie są w międzyczasie blokowane; ze względu na jednowątkowy charakter JavaScript jest to preferowany sposób. Wrzucam to ze względu na kompletność, ale pierwsza metoda jest bardziej wydajna i lepiej pasuje do node.js, więc zrób to, chyba że w grę wchodzi poważne przepisanie.
To nic nie warte, że oba przypadki polegają na asynchronicznych wywołaniach zwrotnych, co oznacza, że każdy kod poza nim może potencjalnie zostać uruchomiony, zanim inne zostaną skończone. Np. używając naszego pierwszego fragmentu:
function getStudentsData(callback) {
//[...]
}
getStudentsData(function(dataList) {
//[...]
});
console.log("hello world");
Ten ostatni plik console.log jest prawie gwarantowany przed uruchomieniem naszego wywołania zwrotnego do getStudentsData. Obejście? Zaprojektuj go, tak właśnie działa node.js. W powyższym przypadku jest to łatwe, po prostu wywołalibyśmy console.log tylko w naszym wywołaniu zwrotnym przekazany do getStudentsData, a nie poza nim. Inne scenariusze wymagają rozwiązań, które odbiegają nieco bardziej od tradycyjnego kodowania proceduralnego, ale kiedy już to opanujesz, przekonasz się, że bycie sterowanym zdarzeniami i brak blokowania jest w rzeczywistości dość potężną funkcją.