Eu seguiria o caminho que você sugere em sua pergunta e anexaria um retorno de chamada personalizado à sua função de busca:
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
});
Esse é provavelmente o método mais eficiente; alternativamente, você pode confiar em uma velha escola
while
loop até que os dados estejam prontos: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);
}
});
Usamos
process.nextTick
em vez de um while
real para garantir que outras solicitações não sejam bloqueadas nesse meio tempo; devido à natureza de thread único do Javascript, esta é a maneira preferida. Estou adicionando isso por uma questão de completude, mas o método anterior é mais eficiente e se encaixa melhor com node.js, então vá em frente, a menos que uma grande reescrita esteja envolvida. Não vale a pena que ambos os casos dependam de retornos de chamada assíncronos, o que significa que qualquer código fora dele ainda pode ser executado antes que outros sejam concluídos. Por exemplo, usando nosso primeiro snippet:
function getStudentsData(callback) {
//[...]
}
getStudentsData(function(dataList) {
//[...]
});
console.log("hello world");
É quase garantido que o último console.log seja executado antes que nosso retorno de chamada passado para getStudentsData seja acionado. Gambiarra? Projete para isso, é assim que o node.js funciona. No nosso caso acima é fácil, apenas chamaríamos console.log somente em nosso retorno de chamada passado para getStudentsData e não fora dele. Outros cenários exigem soluções que se afastam um pouco mais da codificação procedural tradicional, mas, uma vez que você se familiarize com isso, descobrirá que ser orientado a eventos e sem bloqueio é realmente um recurso bastante poderoso.