2016-08-04 4 views
1

Ich mache eine Funktion, die Daten so oft aktualisiert, und ich habe Probleme mit der Anforderungskette, die ich habe. Das Problem ist, dass ich eine for-Schleife habe, die die asynchronen Anträge laufen lässt und die for-Schleife beendet, bevor die Anträge beendet werden.Knoten js for-loop Warten auf asynchrone Funktion vor der nächsten Iteration?

setInterval(function(){ // this updates the total hours of all members every 10 seconds 
    request({ // this gets all of the loyalty program members 
     url: "",//omitted 
     method: "GET" 
    }, 
     function(listError, listResponse, listBody) { 
      if(listError == null && listResponse.statusCode == 200) { 
       var varBody = {}; 
       var listObj = JSON.parse(listBody); 
       for(var i = 0; i < listObj.result.length; i++) { // parses through all of the members to update their hours 

        console.log(i);//****PRINT STATEMENT 

        varBody.index = i; 
        varBody.memberID = listObj.result[i].program_member.id; 
        request({ //we do this request to get the steam ID of the program member 
          url: "",//omitted 
          method: "GET" 
         }, 
         function(fanError, fanResponse, fanBody) { 

          var fan = JSON.parse(fanBody); 
          if(fanError == null && fanResponse.statusCode == 200 && fan.result.profiles.length != 0) { // make sure that the profile isn't empty 
           request({ 
             url:"",//omitted 
             method: "GET" 
            }, 
            function(hourError, hourResponse, hourBody) { 
             if (hourError == null && hourResponse.statusCode == 200) { 
              var gameList = JSON.parse(hourBody); 
              var minutes = 0; 
              for (var j = 0; j < gameList.response.games.length; j++) { // for loop to calculate the minutes each user has on steam 
               minutes += gameList.response.games[j].playtime_forever; 
              } 
              var deltaHours = 1; 
              if(deltaHours != 0) { 
               var transaction = { // updated member object to be inserted 
                pointsearned: deltaHours, 
                pointsused: 0, 
                loyaltyprogram_id: loyaltyID, 
                programmember_id: memberID 
               }; 
               request({ // POST request to update the member 
                 url: "",//omitted 
                 method: "POST", 
                 body: JSON.stringify(transaction), 
                 headers: { 
                  "Content-Type": "application/json" 
                 } 
                }, 
                function(updateError, updateRes, updateBody) { 
                 if(updateError == null && updateRes.statusCode == 200) { 
                  console.log("Success");//****PRINT STATEMENT 
                 } 
                } 
               ); 
              } 
             } 
            } 
           ); 
          } 
         } 
        ); 
       } 
      } 
      console.log("Users Updated"); //****PRINT STATEMENT 
     } 
    ); 
}, 10000); 

Wenn ich diesen Code auszuführen, wäre es drucken:

0 
1 
2 
3 
Success 
Success 
Success 
Success 

Ich weiß, was das Problem ist. Es ist die Tatsache, dass die for-Schleife nicht auf die Beendigung der Anforderungen wartet. Was ich nicht weiß, ist ein Workaround dafür. Hat jemand irgendwelche Ideen?

+0

Haben Sie die Anfragen „parallel“ senden wollen oder möchten Sie sequentialy sie schicken, ein nach dem anderen? – hugomg

+0

Verwenden Sie außerdem bereits eine "Control Flow" -Bibliothek für Ihre Async-Dateien? Schleifen in Async-Code sind lästig, um von Hand zu tun ... – hugomg

+0

Ich möchte, dass sie nacheinander ausgeführt werden. Ich verwende keine Kontrollfluss-Bibliothek, die ich kenne. – NightShadows

Antwort

4

Sie möchten die async Bibliothek.

wie dies in async
async.forEachOf(listObj.result, function (result, i, callback) { 
    varBody.index = i; 
    varBody.memberID = result.program_member.id; 
    request(
     ... 
    , function() { 
     // Do more Stuff 
     // The next iteration WON'T START until callback is called 
     callback(); 
    }); 
}, function() { 
    // We're done looping in this function! 
}); 

Es gibt viele praktische Utility-Funktionen, die viel mit Rückrufe Arbeit viel einfacher macht:

Zum Beispiel

for(var i = 0; i < listObj.result.length; i++) { 
    varBody.index = i; 
    varBody.memberID = listObj.result[i].program_member.id; 
    request(
     ... 
    , function() { 
     // Do more Stuff 
    }); 
} 

kann wie folgt stattdessen geschrieben werden.

7

Für Vollständigkeit, die Art und Weise async Dinge der Reihe nach „von Hand“ zu tun ist, Rekursion zu verwenden:

function dothings(things, ondone){ 
    function go(i){ 
     if (i >= things.length) { 
      ondone(); 
     } else { 
      dothing(things[i], function(result){ 
       return go(i+1); 
      }); 
     } 
    } 
    go(0); 
} 
+0

Dies ist eine wirklich clevere Lösung. – jason

Verwandte Themen