2012-03-29 4 views
2

ich ein wenig verwirrt bin, wie zu bestimmen, wann async Funktion mehrmals von einem anderen genannt einen Anruf von der letzten Iteration beendet ist:jQuery JavaScript Nested Asynchronous Callback-Funktionen

function MainAsyncFunction(callback) { 
    for (var i = 0; i < 10; i++) { 
    SubAsyncFunction(function(success) { 
     if (i >= 10 && success) { // THIS IS WRONG?! 
     callback(true); // happens too early 
     } 
    }); 
    } 
}; 

function SubAsyncFunction(callback) { 
    SubSubAsyncFunction(function() { 
     callback(true); 
    }); 
} 

Was ich tue, ruft die Google Distance Matrix service, die eine Beschränkung von 25 Zielen hat, daher muss ich meine Reihe von Zielen aufteilen, um diesen Dienst mehrere Male zu nennen, aber ich verstehe nicht, wenn es fertig ist.

und im Haupt-Bit des Codes kann ich sagen, dass die zweite Iteration der Schleife in der MainAsyncFunction ist noch nicht abgeschlossen, wenn es einen Rückruf durchführt.

Ich denke, mein Problem ist, dass ich mich nicht mit der Reihenfolge der Ereignisse beschäftigt habe, wenn es um asynchrone Funktionen in JavaScript geht ... bitte erläutern Sie, wie das Thema normalerweise erreicht wird.

Antwort

7

Sie könnten das Objekt jQuery Deferred verwenden, das als Token fungiert und den Status einer asynchronen Operation darstellt.

Das folgende ist ein vereinfachtes Beispiel:

//set up your sub method so that it returns a Deferred object 
function doSomethingAsync() { 
    var token = $.Deferred(); 
    myAsyncMethodThatTakesACallback(function() { 
     //resolve the token once the async operation is complete 
     token.resolve(); 
    }); 
    return token.promise(); 
}; 

//then keep a record of the tokens from the main function 
function doSomethingAfterAllSubTasks() { 
    var tokens = []; 
    for (var i=0; i < 100; i++) { 
     //store all the returned tokens 
     tokens.push(doSomethingAsync()); 
    } 

    $.when.apply($,tokens) 
     .then(function() { 
      //once ALL the sub operations are completed, this callback will be invoked 
      alert("all async calls completed"); 
     }); 
}; 

Das Folgende ist eine aktualisierte Version des aktualisierten Code des OP:

function MainAsyncFunction(callback) { 
    var subFunctionTokens = []; 
    for (var i = 0; i < 10; i++) { 
    subFunctionTokens.push(SubAsyncFunction()); 
    } 

    $.when.apply($,subFunctionTokens) 
    .then(function() { 
    callback(true); 
    }); 
}; 

function SubAsyncFunction() { 
    var token = $.Deferred(); 
    SubSubAsyncFunction(function() { 
     token.resolve(); 
    }); 
    return token.promise(); 
};​ 
+0

ich meinen Code vereinfacht, wäre dies für mich noch? – Tsar

+0

Ja, das würde immer noch funktionieren. Geben Sie mir einen Moment und ich werde Ihren neuen Code konvertieren ... –

+0

@Tsar siehe meine Bearbeitung –

0

Vielleicht die ajaxStop() event? Dies ist ein jQuery-Ereignis, das nur ausgelöst wird, wenn alle aktiven AJAX-Anforderungen abgeschlossen sind.

0

Das Problem ist, dass der Wert von i ständig in die wechselnden ist Schleife, die nach dem Scheitern der Schleifenbedingung schließlich außerhalb der Grenzen liegt.

Der einfachste Weg, dies zu beheben ist:

for(i=0; i<5; i++) { // or whatever your loop is 
    (function(i) { 
     // the value of i is now "anchored" in this block. 
    })(i); 
} 
+0

Oder verwenden Sie '$ .Each (Daten, Funktion (Index, Element) {...})' –

+0

Wenn Sie den Code durch mehrere hundert Befehle ohne guten Grund aufblasen wollen, sicher, knock out ... –

+0

Angenommen, Sie beziehen sich auf jQuery, das OP verwendet es bereits (er enthält das Tag), so dass er "jedes" kostenlos erhält und ich persönlich denke, dass es etwas lesbarer ist. Punkt genommen, obwohl –