Marco: Ajax Requests in Schleife

Hallo,

In einem Javascript habe ich eine Schleife innerhalb einer Funktion. Darin werden mit Hilfe von Ajax mehrere Objekte versendet:

(Mit Prototypejs.org Framework)

  
  
function senden() {  
for(var i=0; i<5; i++) {  
req = i;  
 // Execute the request  
  new Ajax.Request(URL, {  
   async: false,  
   method: 'post',  
   postBody: req,  
   evalScripts: false,  
   onFailure: this.fehlerbehandlung,  
   onSuccess: this.erfolgreich  
  });  
}  
  
return true; // Wenn erfolgreich  
}  
  

Nun möchte ich dass wenn die Schleife zu Ende ist und ALLE Objekte erfolgreich versendet wurden, die Funktion "true" zurückgibt. Das Problem ist, dass durch die asynchronizität das erschwert weil man nicht weiss WANN alles versendet wurde, bzw die Funktion gibt "true" zurück bevor alle Objekte gesendet wurde. Gibt es dafür eine Lösung?

Viele Grüsse
Marco

  1. hi,

    Nun möchte ich dass wenn die Schleife zu Ende ist und ALLE Objekte erfolgreich versendet wurden, die Funktion "true" zurückgibt. Das Problem ist, dass durch die asynchronizität das erschwert weil man nicht weiss WANN alles versendet wurde, bzw die Funktion gibt "true" zurück bevor alle Objekte gesendet wurde.

    Natürlich - genau das bedeutet ja asynchron - feuer ab, und warte _nicht_ auf die Ergebnisse.

    Gibt es dafür eine Lösung?

    Entweder du stellst auf synchron um - nicht unbedingt zu empfehlen, damit kannst du die Seite komplett lahmlegen, wenn ein Request schiefgeht - oder du bleibst bei asynchron, und verzichtest auf das liefern eines Rückgabewertes aus dieser Funktion - und triggerst das, was du von diesem Rückgabewert abmachen wolltest, irgendwie anders (bspw. mit einem Counter, der bei nach jedem erfolgreich abgeschlossenen Request um eins erhöht wird).

    gruß,
    wahsaga

    --
    /voodoo.css:
    #GeorgeWBush { position:absolute; bottom:-6ft; }
    1. Hi,

      Hmmm, ich habe ja auf Synchron umgestellt (mit Parameter async = false).

      In this.erfolgreich habe ich darum versucht mit this.status = 'erfolgreich' eine Variable zu setzen die ich dann jeweils in der Hauptroutine in Intervallen abfrage. Das Problem in diesem Fall (bei der Benutzung von setInterval(prüfeStatus, 1000)) ist, dass die Methode prüfeStatus offenbar keine Statusaktualiserung "erhält", d.h. die Werte bleiben immer im ursprünglichen Zustand...

      Gruss Marco

  2. Hallo Marco,

    Nun möchte ich dass wenn die Schleife zu Ende ist und ALLE Objekte erfolgreich versendet wurden, die Funktion "true" zurückgibt.

    D.h. Dir ist es aus irgendeinem Grund wichtig, dass die Funktion erst beendet, wenn alle Requests durch sind? Wenn ja, würde ich in der Funktion darauf warten, dass alle Requests beendet sind und dann in Abhängigkeit von Erfolgreichsein aller Requests entweder Wahr oder Falsch zurückgeben. D.h. Du brauchst etwas, dass den aktuellen Status der Requests (und ihren eventuellen Erfolg) mitloggt. Ungefähr so:

    ~~~javascript function send() {
            var status = {
                  reqCount: 0,
                  success: true,
                  done: false;
                  register: function () {
                      this.reqCount++;
                  },
                  unregister: function (successful) {
                    this.reqCount--;
                    this.success = this.success && successfull;
                    if (this.reqCount == 0) {
                        this.done = true;
                    };
                  },
                  areWeDoneYet: function () {
                      while (!done) { /* Tue nix */ };
                      return success;
                  }
            }

    (5).times(function (i) {
                new Ajax.Request(URL, {
                    method: "post",
                    postBody: i,
                    evalScripts: false,
                    onUninitialized: function () {
                        status.register();
                    },
                    onFailure: function () {
                        status.unregister(false);
                        this.fehlerbehandlung();
                    },
                    onSuccess: function (xhr) {
                        status.unregister(true);
                        tuewasdamit(xhr);
                    }
                });
            });

    return status.areWeDoneYet();
        }

      
    (Etwas zu ausführlich, der Code. Und ungetestet. Obacht!)  
      
    Jeder Request registriert sich beim Erzeugen und meldet sich beim Beenden mit dem Resultat des Gelingens des Requests wieder ab. In Abhängigkeit dieser beiden Faktoren haben wir also einen Status ob die Funktion fertig ist und ob das Gesamtresultat erfolgreich ist. Das kann man nun wiederholt abfragen (die while-Schleife) und beim Erreichen des Ziels dann zurückgeben. status.areWeDoneYet() übernimmt also das Warten auf Beendigung der Requests.  
      
    Prototype hat übrigens eine Möglichkeit global den Status von Ajax-Requests zu verfolgen und zwar mit [Ajax.Responders](http://prototypejs.org/api/ajax/responders), nach dem ich das status-Objekt nachgeahmt habe. Allerdings geschieht das global für alle mit Ajax.Request erzeugten Requests und eventuell hast Du noch andere Requests. Deswegen die lokale Statusüberwachung.  
      
    Und nun die schlechte Nachricht: Ich würde obigen Code NICHT benutzen. Und zwar dient dieser nur dazu ein Asynchrones Modell in ein synchrones Korsett zu zwingen; meiner Meinung nach unnötigerweise. Wozu auf das Beendigen aller Requests warten? Das ganze Skript kann, wie schon von wahsaga gesagt, die Seite für längere Zeit lahmlegen, wegen der beknackten while-Schleife. Und das nur, weil Du in der äusseren, offenbar linear ablaufenden Routine eine zurückgegebenes True brauchst.  
      
    Das wäre der wirkliche Knackpunkt und die Frage, die ich mir stellen würde. Wozu brauchst Du dieses True überhaupt? Für Fehlerbehandlung? Das lässt sich doch genausogut über die Callbacks der Requests lösen - oder über eine Callbackbasierten Statussammlung. Ich würde also versuchen, die äussere Logik callback-basiert umzuschreiben um von einer linearen Routine auf ein ereignisgesteuertes Modell zu kommen. Durch die Callbacks sind die entsprechenden Code-Abschnitte immer noch verknüpft, aber es fehlt dann das explizite Warten. Da wir nicht wissen, was Du damit bezwecken willst, kann man da auch nicht mehr sagen.  
      
      
    Tim