Teil 6: AJAX - das XMLHTTP-Objekt
Der Normalfall Ihrer Anwendungsfälle von AJAX dürfte die asynchrone Verarbeitung sein, denn hierbei kann AJAX alle seine Muskeln spielen lassen. Allerdings müssen Sie als Webprogrammierer nun Ihr JavaScript so ähnlich schreiben, als würden Sie gerade eine GUI-Anwendung für den PC gestalten - funktional ist das ja gerade das, was Sie erreichen wollen.

© Archiv
Sie definieren bei asynchroner Verarbeitung bei jedem X-Objekt eine Callback-Funktion, dann senden Sie den Request zum Server und machen normal weiter. Sie kehren also aus JavaScript zurück und warten darauf, was dem Benutzer noch einfällt. Sobald die Server- Antwort da ist, wird Ihr Callback aufgerufen, und darin machen Sie nun das, was mit den Daten vom Server zu geschehen hat. Die Bearbeitung der Benutzer-Aktion wird also in zwei Teile aufgesplittet
in das, was sofort zu passieren hat mit
- optional sofortigen Änderungen im Dokument,
- Datensammlung und Vorbereitung des XObjekts,
- Eintragen der Antwort-Prozedur,
- Senden des Requests zum Server,
- Rücksprung zum Anwender/Aufrufer und
in die Antwort-Prozedur mit
- Prüfen der Response-Codes und Fehler-Aktionen sowie
- Auswerten und Verarbeiten der Antwort- Daten.
Manche AJAX-Beispiele im Internet arbeiten übrigens mit dem normalen JavaScript onload- Event anstelle des standard-gemäßen X.onreadystatechange. Tun Sie das nicht, bleiben Sie besser bei der standard-konformen X.onreadystatechange = AntwortProzedur;. Denn leider funktioniert der onload- Event nur bei einigen Browsern - so schön es auch sonst wäre.
Unter Umständen wird es bei der Server-Verarbeitung schon zu einer zweiten und dritten Benutzer-Aktion kommen, d.h. Sie haben es dann mit mehreren parallel laufenden Requests zu tun. Beachten Sie deshalb:
Jeder Request braucht sein eigenes X-Objekt: Legen Sie mindestens so viele X-Objekte an, wie sich selbst bei langsamer Server- Verbindung gleichzeitige Requests absetzen lassen.
Verwenden Sie dasselbe X-Objekt erst wieder, wenn Sie nach einem readyState 4 die Daten verarbeitet haben. Rufen Sie zum Initialisieren des alten Objekts X.abort() auf - der IE braucht das.
Die Server-Antworten können in anderer Reihenfolge eintrudeln, als die Requests gesendet wurden.
In der Praxis arbeiten Sie deshalb gleich besser mit einem Satz von X-Objekten und weisen mit jedem Request einfach das nächste Objekt zu. Die Zuweisung eine Objekts, das Eintragen der Callback-Funktion und den Aufruf des Servers legen Sie am besten gleich in eine Funktion, um sich im Anwendungscode nicht um Details kümmern zu müssen. Im Folgenden weisen Sie mehrere Objekte in einem Round-Robin Verfahren zu, die Sie so auch gleich verwenden können:
// Array von X-Objekten var Xobjekt = new Array (null, null, null, null, null, null, null, null); var Xn = 0; // Index des aktuellen Xobjekt[] // Zuweisen und AJAX-Aufruf function callServer(url,callback_function) { if (!Xobjekt[Xn]) { Xobjekt[Xn] = newXobjekt(); } else { Xobjekt[Xn].abort(); } Xobjekt[Xn].open('GET',url); Xobjekt[Xn].onreadystatechange = new Function("var x = " + Xn + "; " + "if(Xobjekt[x].readyState != 4) return; " + "if(Xobjekt[x].status == 200) " + callback_function + "(Xobjekt[x].responseText); " + "else " + "alert('ERROR ' + Xobjekt[x].status + ' when calling " + url + "'); "); Xobjekt[Xn].send(null); Xn++; // Positionieren auf nächstes Xobjekt (Modulo Array-Länge) if (Xn >= Xobjekt.length) Xn = 0; }
Fehlerabfragen liegen jetzt auch sinnvollerweise in den zentralen Prozeduren, die Callback- Funktion wird nur mit den Nutzdaten als Parameter aufgerufen. Für den onreadystatechange generieren Sie bei jedem Request eine neue Funktion, die den zum Request dazugehörenden Callback gleich mit enthält, weiteres Book-Keeping wird dadurch unnötig.
Wenn Sie einen Request absetzen, gestalten Sie dies mit zentralen AJAX-Routinen in zwei Zeilen. Sie übergeben einfach die URL und Call-Back Funktion, letztere auch als Text- String:
function deletePicture(n) { var url = 'pix_do.php?action=delete&id=' + n + '&resolution=<?php echo $pix_thumbnail_resolution; ?>'; callServer(url, 'editAnswer'); }