Zwei Helden

Im Laufe der letzten zehn Jahre ist die Anzahl der Techniken, die das Web dynamischer gestalten, stetig gestiegen. Unter dem Namen Ajax erregt seit kurzem eine Idee Aufsehen, die nicht wie DHTML und Flash die Darstellung von Webseiten beleben soll, sondern bei der Kommunikation zwischen Browser und Webserver ansetzt und asynchron XML-Nachrichten austauscht.

In Pocket speichern vorlesen Druckansicht 47 Kommentare lesen
Lesezeit: 12 Min.
Von
  • Stefan Mintert
Inhaltsverzeichnis

Als Ende 1995 Netscape seinen Browser mit einer eigenen Programmiersprache ausstattete, dienten die ersten Listing-Beispiele dazu, HTML-Formulare „smart“ zu machen. Das Formular war etwa in der Lage, gewisse Eingabefehler (beispielsweise ein Buchstabe in einer Telefonnummer, E-Mail-Adresse ohne @-Zeichen) zu erkennen und den Benutzer darauf hinzuweisen. Die Verbesserung bestand vor allem darin, dass der Browser den Fehler erkennt und nicht erst die Formulardaten an den Server überträgt, der mit der Fehlermeldung antwortet. 1995, als die Leitungen noch etwas schmaler waren, stellte dieser Ansatz einen wichtigen Schritt dar, um Webanwendungen schneller und damit komfortabler zu gestalten.

Bei der Verarbeitung steckt die gesamte Logik im Client, genauer im Javascript-Programm, das er ausführt. Das ist ein guter Ansatz, wenn die Logik nicht auf große Datenmengen zugreifen muss, um ihre Arbeit zu erledigen. Zur Illustration folgendes Szenario: Ein HTML-Formular erlaubt die Eingabe einer Adresse mit Postleitzahl, Ort und Straße. Nun heißt es, die Plausibilität der Eingabe zu prüfen. Es geht um die Beantwortung der Frage, ob in der genannten Stadt das genannte Postleitzahlgebiet und die genannte Straße liegen.

Der klassische Ansatz besteht in der Überprüfung der Daten auf der Serverseite nach einem „Submit“ des Formulars. Andererseits wäre es bei Verwendung von Javascript im Client notwendig, die Information über alle Straßen in Deutschland zur Überprüfung an den Browser zu senden. Beide Ansätze sind nicht optimal und genau hier setzt Ajax an. Bei dieser Idee schickt der Browser die eingegebenen Daten ohne Zutun und ohne dass der Benutzer es merkt an den Server. Der überprüft die Daten und schickt eine Nachricht, die das Ergebnis der aufwendigen Prüfung enthält, an den Browser zurück. Dieser reagiert auf das zurückgelieferte Ergebnis, etwa mit einer Fehlermeldung, dass die eingebene Straße nicht im eingegebenen Postleitzahlengebiet liegt.

Während der Benutzer nur dreimal etwas tut, tauschen Browser und Webserver fast ständig Nachrichten aus (Abb. 1).

Ajax steht für „Asynchronous Javascript And XML“. Dass Javascript und XML - gleichsam die beiden Helden namens Ajax aus Homers Troja-Epos - eine Rolle spielen, ist keine Überraschung mehr. Das Wesentliche aber ist die Asynchronität. Zur Veranschaulichung siehe Abbildung 1; zunächst die linke Seite. Die Kommunikation zwischen Browser und Server, die der Benutzer wahrnimmt, ist die, die seine Aktionen auslösen: das Anklicken eines Links oder das Abschicken eines Formulars. Den Takt der Kommunikation gibt der Benutzer vor (im Bild als diskrete Zeitpunkte t=1,2,3 dargestellt); zwischen den Takten redet der Browser normalerweise nicht mit dem Server. Bei Ajax ist das anders.

Mehr Infos

Hier kann ein Script (in der Regel Javascript, daher das „J“ in „Ajax“) eine Kommunikation außerhalb des Benutzertaktes auslösen (im Bild als rote Pfeile dargestellt). Der Server antwortet mit einer XML-Nachricht, die Javascript als DOM-Objekt zur Verfügung steht.

Schon nach dem Eintippen des zweiten Zeichens kontaktiert das Javascript-Programm den Server und gibt nach dessen Antwort die infrage kommenden Abkürzungen aus (Abb. 2).

So weit die Theorie. Wie die Praxis aussieht, beantwortet die folgende Anwendung. Sie stützt sich auf ein Glossar von XML-Fachbegriffen, den „XML Acronym Demystifier“ (siehe „Online-Ressourcen“). Dieses Glossar liegt als circa 380 KByte große XML-Datei vor.

Abbildung 2 zeigt diese Anwendung. Ein Formular erlaubt die Eingabe einer unvollständigen Abkürzung aus dem Themenbereich XML. Das Ajax-Prinzip zeigt sich in dieser Anwendung dahingehend, dass sie schon während der Eingabe von Zeichen die Ergebnisse anzeigt, ohne vorab das gesamte Glossar zu laden.

Listing 1 enthält den wesentlichen Teil des Javascript-Codes. Der Einstieg in ihn beginnt beim HTML-Formular. Das Eingabefeld ist mit zwei Event-Handlern ausgestattet:

<input onkeyup="if (this.value.length &gt; 1)
{ loadAcroList(this.value) ;}"
onblur="if (this.value.length &lt; 2)
{ loadAcroList(this.value); }" type="text"/>
Mehr Infos

Listing 1: XML-Akronyme lesen

function loadAcroList(acro) {
if (acro != "")
{
setCursor('wait');
if (req && (req.readyState == 2 || req.readyState == 3)) {
req.abort();
// falls ein Request läuft, diesen abbrechen
}

loadXMLDoc('getentry/?acro='+acro);
}
}

function loadXMLDoc(url) {
if (window.XMLHttpRequest) {
// Test, ob der Browser ein eingebautes XMLHttpRequest-Objekt besitzt
req = new XMLHttpRequest();
// Event-Handler am Objekt registrieren
req.onreadystatechange = processReqChange;

// Request absetzen
req.open("GET", url, true);
req.send(null);
} else if (window.ActiveXObject) {
// ... oder ob er das Objekt per ActiveX implementiert
req = new ActiveXObject("Microsoft.XMLHTTP");
// Event-Handler am Objekt registrieren
req.onreadystatechange = processReqChange;

// Request absetzen
req.open("GET", url, true);
req.send();
}
}

function processReqChange() {
// falls Status "4" (complete) erreicht ist, geht's los
if (req.readyState == 4) {
// aber nur, falls der Server HTTP-Statuscode 200 gesendet hat
if (req.status == 200) {

// Neue Akronym-Liste anzeigen
showAcroList();

// Mauszeiger auf Normalzustand zuruecksetzen
setCursor('auto');
} else {
alert("Fehler bei der Kommunikation mit dem Server:\n" +
req.statusText);
}
}
}

Den ersten Event-Handler aktiviert ein Tastendruck (onkeyup). Falls die eingegebene Zeichenkette wenigstens aus zwei Zeichen besteht, lädt das Skript die Liste der passenden Akronyme aus dem Glossar. Dafür ist die Funktion loadAcroList() zuständig. Die Einschränkung auf eine Mindestlänge von zwei Zeichen ist nicht notwendig. Sie soll dafür sorgen, dass die übertragene Datenmenge nicht zu groß wird, indem schon die Eingabe des ersten Zeichens eine Datenübertragung auslöst. Sollte der Benutzer tatsächlich nur ein Zeichen eingeben, so sorgt onBlur beim Verlassen des Eingabefeldes für das Laden der Akronym-Liste sogar in diesem Fall.

loadAcroList() setzt zunächst den Mauszeiger in den Zustand „wait“. Man kann darüber diskutieren, ob es sinnvoll ist, eine asynchrone Kommunikation überhaupt für den Benutzer sichtbar zu machen. Sollte die Datenübertragung zum Server lange dauern, kann es nützlich sein, wenn der Benutzer ein Indiz für die ansonsten unmerkliche Kommunikation bekommt. setCursor() ist für diesen Artikel eine gute Option, den Wechsel zwischen den Status zu veranschaulichen.

Im Wesentlichen ist loadAcroList() ein anwendungsspezifischer Wrapper für die universelle Funktion loadXMLDoc() (siehe das Apple-Dokument in den „Online-Ressourcen“). Sie setzt einen Get-Request an die per Parameter übergebene URL ab. Dabei unterscheidet die Funktion zwischen unterschiedlichen Browsern und versteckt die jeweilige Implementierung vor dem Programmierer.

Da loadXMLDoc() die zentrale Aufgabe in der Ajax-Programmierung übernimmt, lohnt sich ein genauer Blick: Zunächst wird ein neues Objekt für den gewünschten Request erzeugt. Es handelt sich um ein so genanntes XML-HTTP-Request-Objekt. In der Ausprägung der Erfinderin Microsoft sieht die Objekterzeugung so aus:

req = new
ActiveXObject("Microsoft.XMLHTTP");

Bei Browsern der Mozilla-Welt hingegen:

req = new XMLHttpRequest();

Einige Zeilen darunter wird die HTTP-Get-Verbindung durch req.open(„GET“, url, true) initialisiert. “GET“ ist die Angabe der HTTP-Methode, url die gewünschte Zieladresse und true gibt an, dass die Kommunikation asynchron erfolgen soll. Ändert man diesen Parameter zu false, führt das dazu, dass das Programm beim Ausführen der send()-Methode bis zur Beendigung der Kommunikation blockiert.

Bis hierher ist das Vorgehen offensichtlich: Erzeugen eines XML-HTTP-Request-Objekts und Aufruf der Methoden open() und send() auf dieses Objekt bezogen. Die Dauer bis zu einer Antwort über eine HTTP-Verbindung ist von vielen Faktoren abhängig und kann durchaus eine spürbare Zeit in Anspruch nehmen. Dank der Asynchronität läuft das Programm zwischenzeitlich weiter. Was passiert aber, sobald die HTTP-Antwort eintrifft?

Um darauf reagieren zu können, muss man eine Funktion definieren und sie an die Property onreadystatechange des Request-Objekts binden.

req.onreadystatechange = processReqChange;

Die Funktion processReqChange() wird nur aktiv, wenn der Zustand 4 (vollständig) eingetreten ist - die anderen Zustände sind 0 (nicht initialisiert), 1 (bereit), 2 (gesendet) und 3 (interaktiv). Falls der Server mit dem HTTP-Code 200 geantwortet hat, zeigt die Funktion showAcroList() die geladenen Akronyme als Teil der Webseite an. Anschließend setzt setCursor(‚auto’) den Mauszeiger auf den Normalzustand zurück.

Das Ergebnis des HTTP-Get-Requests steht in verschiedenen Properties des Request-Objekts zur Verfügung. Details sind der Microsoft-Webseite (siehe die „Online-Ressourcen“) zu entnehmen. Falls die Antwortnachricht mit dem MIME-Typ „text/xml“ versehen ist, ist der Rumpf der Nachricht im Property req.responseXML als DOM-Objekt zu finden. Die weiteren Schritte auf Seiten der Browser-Programmierung sind übliche DOM-Programmzeilen. Da sie keine neuen, Ajax-spezifischen Erkenntnisse mit sich bringen, sei auf den Abdruck verzichtet. Das vollständige und lauffähige Listing ist im Netz zu finden (siehe „Online-Ressourcen“). Für die DOM-Programmierung sei hier noch gezeigt, wie man im Javascript-Programm an die übertragenen Akronyme gelangt. Dazu muss man wissen, dass die Einträge im XML-Glossar in Elementen der Form <Acronym>...</Acronym> eingebettet sind. Alle Acronym-Elemente, die der asynchrone Request geliefert hat, sind per

req.responseXML. getElementsByTagName("Acronym")

zugänglich. Bei getElementsByTagName() handelt es sich um die durch das W3C-Objektmodell definierte Methode.

Abschließend sei betont, dass die Technik keineswegs Asynchronität, Javascript oder XML voraussetzt. Die Konsequenz der synchronen Kommunikation ist das Blockieren des Programms, wie oben erwähnt. Die Microsoft-Dokumentation zeigt neben JScript Codeschnipsel für die Benutzung des XML-HTTP-Objekts aus anderen Sprachen heraus, beispielsweise C. Und falls keine XML-Nachricht übertragen wird, sondern „text/html“ oder „text/plain“, steht der Nachrichtenrumpf als Zeichenkette in einer Property des Objekts.

Auf Grund seiner Asynchronität erlaubt Ajax das parallele Verschicken von HTTP-Requests. Nach dem Absenden läuft die Javascript-Anwendung weiter, und erst bei Eintreffen der HTTP-Antwort wird die Methode onreadystatechange am jeweiligen Objekt aufgerufen (Event Handling).

Um mehrere Requests parallel abzusetzen, ist es notwendig, für jeden Request eine eigene Callback-Methode zu definieren und dem jeweiligen Objekt zuzuweisen. Schematisch sieht das aus wie Listing 2.

Mehr Infos

Listing 2: Parallele Requests

// Definition der Callback-Funktionen
function callbackA() {
if (requestObjectA.readyState == 4) {
...
}
}

function callbackB() {
if (requestObjectB.readyState == 4) {
...
}
}

//Request-Objekte erzeugen
requestObjectA = new XMLHttpRequest();
requestObjectB = new XMLHttpRequest();

// Event-Handler registrieren
requestObjectA.onreadystatechange = callbackA;
requestObjectB.onreadystatechange = callbackB

Die so initialisierten Objekte können zu einem beliebigen Zeitpunkt eine Verbindung öffnen und einen Request absenden. Es versteht sich von selbst, dass die jeweiligen Callback-Methoden keine konkurrierenden Anweisungen ausführen sollten.

Im Fall der XML-Akronyme kann es tatsächlich zu Konflikten kommen. Hier besteht der Stolperstein darin, dass das Skript nur ein einziges Request-Objekt verwendet. Da der Auslöser für das Senden des Requests ein Tastendruck ist, muss das Programm mit der Situation umgehen, dass ein Request gesendet werden soll, noch bevor der vorhergehende verarbeitet ist. Das geschieht in der Funktion loadAcroList().

if (req && (req.readyState == 2 
|| req.readyState == 3)) {
req.abort(); // falls ein Request läuft, ihn abbrechen
}

Die if-Anweisung überprüft, ob das Request-Objekt existiert und ob es sich im Zustand 2 oder 3 (gesendet oder interaktiv) befindet. In diesem Fall bricht die abort()q-Methode den Request ab, bevor der nächste ausgelöst wird.

Ein oder mehrere globale Objekte zu verwenden ist notwendig, damit die Funktion processReqChange an das Objekt herankommt. Wer es eleganter ohne globale Objekte haben möchte, findet bei IBM einen geschickte Lösung. Der Autor erzeugt dort aus dem Request-Objekt und der gewünschten Funktion eine neue Event-Handler-Funktion, in der das Request-Objekt gekapselt ist (siehe Philip McCarthys Artikel in den „Online-Ressourcen“).

Wie bei allen Browser-Techniken neueren Datums ist die Frage nach der Unterstützung durch die verschiedenen Browser zu stellen. Die Technik selbst ist zwar nicht neu, der Boom um den Namen Ajax ist es aber schon. So ist es nicht überraschend, dass noch nicht alle Browser volle Unterstützung anbieten. Der Internet Explorer und Firefox/Mozilla in aktuellen Versionen unterstützen das XML-HTTP-Objekt, wenngleich es - wie gezeigt - Unterschiede in der Implementierung gibt. Ein Test der Beispielanwendung mit Safari verlief ebenfalls positiv. Anders bei Opera. Dort gibt es erst eine teilweise Implementierung des XML-HTTP-Objekts.

Es soll nicht unerwähnt bleiben, dass der Zugriff auf Daten, die auf einem anderen Server als dem liegen, von dem das Skript stammt, nicht ohne weiteres funktioniert. Will man nicht die Sicherheitseinstellungen des Browsers senken, hilft das Signieren des Skriptes.

Neu an Ajax ist nicht die Technik. Javascript, XML und DOM gibt es seit langer Zeit. Und das XML-HTTP-Request-Objekt hat Microsoft ebenfalls schon vor Jahren eingeführt. Neu ist neben dem Namen „Ajax“ die Veränderung von Web-Anwendungen. Je mehr die Entwickler verstehen, dass die Kommunikation zwischen Browser und Server nicht auf benutzerausgelöste Ereignisse beschränkt ist, desto komfortabler können solche Applikationen sein. Dieser Paradigmenwechsel lässt Web-Anwendungen entstehen, die sich immer mehr wie „native“ Applikationen verhalten. Hierfür entstehen momentan Bibliotheken, wie Ajax-Widgets, die die Entwicklung von komfortablen WUIs - Web User Interfaces - unterstützen.

Stefan Mintert
ist XML-Berater und Inhaber von Linkwerk.com.

In der Printausgabe finden Sie außerdem Artikel zu "Javascript und XML" (E4X) und der WHAT-Arbeitsgruppe samt einem Listing zum <canvas>-Element, wie Safari und die Firefox-5-Beta es kennen.

Mehr Infos

iX-TRACT

  • Ajax erlaubt dem Browser im Hintergrund die asynchrone Kommunikation mit dem Web-Server.
  • Wesentliche Eigenschaften von Ajax sind der Einsatz von Javascript, XML für den Nachrichtenaustausch und asynchrone Kommunikation.
  • Der Einsatzbereich von Ajax liegt vor allem bei komfortableren Web-Anwendungen mit einem hohen Interaktionsgrad.

(hb)