2012-10-10 17 views
5

chciałbym zadać to pytanie, ponieważ nie jestem pewien, czy mam prawo logiki node.jsNode.js i Redis; Oczekiwanie na pętli, aby zakończyć

Mam zestaw identyfikatorów, że muszę zapytać korzystając Redis' get metoda. A po sprawdzeniu pewnej wartości (powiedzmy, że sprawdzam, czy obiekt, który otrzymałem z danym "kluczem" ma pustą nazwę), dodaję je do listy. Oto mój przykładowy kod;

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

      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); 
         } 
        } 
       });  
      } 

    }); 
    console.log("Goes here after checking every single object"); 

Ale jak oczekiwano ze względu na charakter asynchroniczny węzła, bez sprawdzania każdego identyfikatora na liście to wykonuje „Goes tutaj ...”. Moją potrzebą jest zastosowanie pozostałych procedur po sprawdzeniu wszystkich identyfikatorów (mapowanie w bazie danych redis i sprawdzanie nazwy). Ale nie wiem, jak to zrobić. Może gdybym mógł dołączyć wywołanie zwrotne do pętli for i upewnić się, że reszta moich funkcji zaczyna działać po zakończeniu pętli (wiem, że to niemożliwe, ale po prostu dać pomysł)?

Odpowiedz

4

pójdę trasę proponujesz w swoim pytaniu i dołączyć niestandardową oddzwanianie do sprowadzania funkcję:

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 
}); 

to prawdopodobnie najbardziej skuteczny sposób; alternatywnie można polegać na starej szkoły while pętli dopóki dane są 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 rzeczywistej while aby upewnić się, że inne wnioski nie są blokowane w międzyczasie; ze względu na pojedynczy wątek JavaScript jest to preferowany sposób. Zastanawiam się nad tym, aby była kompletna, ale pierwsza metoda jest bardziej wydajna i lepiej pasuje do pliku node.js, więc idź do niego, chyba że chodzi o poważną zmianę.

Nic nie jest warte, że oba przypadki polegają na asynchronicznych wywołań zwrotnych, co oznacza, że ​​dowolny kod poza nim może nadal potencjalnie działać, zanim inne zostaną wykonane. Na przykład poprzez nasz pierwszy fragment:

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

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

console.log("hello world"); 

To ostatnie console.log jest niemal gwarantowane, aby uruchomić przed naszym zwrotna przekazywana do getStudentsData zostanie zwolniony. Obejście? Zaprojektuj go, tak działa node.js. W naszym przypadku powyżej jest to łatwe, po prostu zadzwonimy pod konsolę.log tylko w naszym wywołaniu zwrotnym przekazanym do getStudentsData, a nie poza nim. Inne scenariusze wymagają rozwiązań, które odbiegają nieco od tradycyjnego kodowania proceduralnego, ale gdy już obejrzysz go, okaże się, że jest on sterowany zdarzeniami, a nie blokowanie to naprawdę bardzo potężna funkcja.

+0

Pierwszy przykład nie wydają się działać dla mnie :(Zobacz [to] (https://i.gyazo.com/129b071f39bbd1a1c491638be634b00c.png), wywołanie Redis jest asynchroniczne. log konsoli moich "wyników" będzie pokazany jako pierwszy, ponieważ jest to dokładnie taka sama logika jak w twoim przykładzie, hmmm. –

1

Wypróbuj moduł async dla node.js. Ten moduł ma asynchroniczny dla Any.

3

Wypróbuj moduł finish. Stworzyłem ten moduł, aby poradzić sobie z tym problemem. Jest łatwiejszy w użyciu niż Async, a także zapewnia lepszą wydajność. Oto przykład:.

var finish = require("finish"); 
finish(function(async) { 
    // Any asynchronous calls within this function will be captured 
    // Just wrap each asynchronous call with function 'async' 
    ['file1', 'file2', 'file3'].forEach(function(file) { 
    async(function(done) { 
     // Your async function should use 'done' as callback, or call 'done' in its callback 
     fs.readFile(file, done); 
    }); 
    }); 
}, function(err, results) { 
    // fired after all asynchronous calls finish or as soon as an error occurs 
    console.log(results[0]);console.log(results[1]);console.log(results[2]); 
}); 
+2

Powinien opublikować próbkę kodu, jak również link, w ten sposób, jeśli łącze stanie się martwe, post nie jest bezużyteczny. – Matthew

+0

Pozdrowienia Dodano przykład kodu – Chaoran

+1

WARN: 'finish' aktualnie dławi, jeśli tablica" forEach' jest pusta, i kończy się z "TypeError: nie można odczytać właściwości 'kickoff' nieokreślonego." Zajęło mi trochę czasu, aby to sprawdzić w dół, miej nadzieję, że to uratuje komuś innemu ból![Zobacz problem na Github] (https://github.com/chaoran/node-finish/issues/2). – OJFord

Powiązane problemy