Nachdem unser erstes Web Dojo jQuery Basics zum Thema hatte, ging es im zweiten Web Dojo direkt nach der Sommerpause um das Thema Ajax: Ursprünge, Hintergründe und Umsetzung nativ in JavaScript bzw. mit jQuery.
>> mehr…
Ajax Basics
Ajax steht für Asynchronous JavaScript and XML und stellt ein Programmiermodell dar, bei dem Daten (asynchron) via JavaScript von einem Web Server abgerufen werden, mit denen dann Teile einer Webseite aktualisiert werden, es allerdings nicht zu einem kompletten Neuladen der Seite kommt. Der technische Ursprung von Ajax stammt von Microsoft und geht auf das Ende des letzten Jahrtausends zurück, als die Redmonder Remote-Scripting-Funktionalität in den IE5 einbauten, um damit dynamische Funktionalität in Outlook Web Access zu ermöglichen. Seit IE7 und in allen modernen Browsern (Firefox, Chrome, Safari, …) steht diese Funktionalität nativ in JavaScript mit dem XMLHttpRequest-Objekt zur Verfügung, in IE5/6 muss noch ein spezielles ActiveX-Objekt angesprochen werden. Der Begriff “Ajax” selbst wurde 2004 in einem Essay erstmals erwähnt.
Wichtig ist, dass Ajax wirklich nur das asynchrone Abrufen von Daten bezeichnet. Davon unabhängig sind dynamische UIs, die mit JavaScript erstellt werden, auch wenn diese marketingtypisch häufig als Ajax-Anwendungen deklariert sind.
Vor- und Nachteile
Ajax bringt viele Vorteile für Benutzer einer Webanwendung mit sich. Dazu zählen eine gesteigerte Benutzbarkeit durch ein besseres Reaktionsverhalten einer Anwendung, da keine kompletten Seiten neu geladen werden müssen. Weiterhin werden durch das partielle Laden von Daten Netzwerk- und Server-Ressourcen geschont, das Rendering findet bei reinen/direkten Ajax auf dem Client in JavaScript statt. Diesen Vorteil verliert man bei sog. indirekten Ajax, wo Daten auf dem Server gerendert und an den Client gesendet werden, wie es z.B. bei einem UpdatePanel in ASP.NET der Fall ist. Dafür hat man dort den Vorteil der Einfachheit und dass man für diese dynamische Funktionalität kein JavaScript beherrschen muss.
Doch Ajax hat nicht nur Vorteile. In der Programmierung entstehen einige Herausforderungen: allgemein steigt die Komplexität der clientseitigen Verarbeitung, was die Fehleranfälligkeit erhöht. Zudem müssen sich Entwickler separat um Aspekte wie den Zurück-Button, Browser-Lesezeichen und Suchmaschinen-Auffindbarkeit kümmern, wenn diese Funktionalität abgedeckt werden soll.
Umsetzung: nativ
Will man Ajax-Funktionalität auf eigenen Webseiten ohne Unterstützung z.B. durch ASP.NET nutzen, kann man dies über das Standard-JavaScript-Objekt XMLHttpRequest zu Fuß tun. Doch bereits bei der Initialisierung dieses Objekts gibt es eine erste Stolperfalle. XMLHttpRequest wird zwar von allen aktuellen Browsern unterstützt, doch will man auch IE5- und IE6-kompatibel sein, so muss das Objekt über ein ActiveX-Objekt geholt werden:
1: var ajaxRequest = null;
2: try {
3: ajaxRequest = new XMLHttpRequest();
4: } catch (e) {
5: try {
6: ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
7: } catch (e) {
8: try {
9: ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
10: } catch (e) {
11: ajaxRequest = null;
12: }
13: }
14: }
Ist diese Hürde genommen, lässt sich eine Verbindung zu einem Server mit ajaxRequest.open(…) öffnen, der Request kann dann mit ajaxRequest.send() übermittelt werden. Um allerdings auf die Rückkehr des Requests reagieren zu können, muss zuvor noch das Event onreadystatechange gebunden werden. Dieses Event wird immer dann geworfen, wenn sich der Zustand des XMLHttpRequest-Objekts ändert, also wenn z.B. die Verbindung geöffnet wird oder eine Anfrage gesendet wird. Soll auf die Antwort eines Requests reagiert werden, so muss auf readyState == 4 geprüft werden, worauf man seine individuellen Aktionen ausführen kann. Insgesamt stellt sich der Prozess wie folgt dar:
1: if (ajaxRequest) {
2: ajaxRequest.onreadystatechange = function () {
3: if (ajaxRequest.readyState === 4) {
4: // Bearbeitung der Antwort
5: }
6: };
7:
8: try {
9: ajaxRequest.open("GET", "<Ziel_URL>", true);
10: ajaxRequest.send();
11: } catch (e) {
12: // Fehler
13: }
14: }
In der Bearbeitung muss dann noch der Status der Antwort geprüft werden, bevor der Antwort-Text bearbeitet werden kann, da z.B. auch ein Fehler aufgetreten sein kann. Ob ein Fehler aufgetreten ist, kann über den Statuscode ermittelt werden, den man mit ajaxRequest.status erhält. Bei status == 200 ist z.B. kein Fehler aufgetreten und die Antwort vom Server lässt sich mittels ajaxRequest.responseText verarbeiten. Erwartet man einen JSON-String als Antwort und möchte diesen als Objekt auswerten, muss der responseText mit eval() weiter in ein JSON-Objekt geparst werden. Insgesamt führt das zu folgendem Code:
1: if (ajaxRequest.status === 200) {
2: if (ajaxRequest.responseText) {
3: var entity = eval('(' + ajaxRequest.responseText + ')');
4: // Verarbeitung des JSON-Objekts
5: }
6: }
7: else {
8: // Verarbeitung eines Fehlers
9: }
Umsetzung: mit jQuery
Uff! Das ist ziemlich viel Code für eine einfache Aufgabenstellung. Geht das nicht besser? Ja, geht es, z.B. mit jQuery! In jQuery ist der komplette obige Code äquivalent zu folgendem Snippet:
1: $.ajax({
2: url: '<Ziel_URL>',
3: dataType: 'json',
4: success: function (entity) {
5: if (entity) {
6: // Verarbeitung des JSON-Objekts
7: }
8: },
9: error: function (jqXHR, status, error) {
10: // Verarbeitung eines Fehlers
11: }
12: });
Dabei wird im Erfolgsfall die Antwort automatisch in ein JSON-Objekt umgewandelt, alle Optionen für den Request und die Callbacks können elegant als Properties übergeben werden. Die $.ajax()-Funktion ist eine Möglichkeit, um Daten mit jQuery mittels Ajax von einem Server abzurufen. Sie bietet dabei viele Parameter, die optional gesetzt werden können, was $.ajax() zur flexibelsten Ajax-Variante in jQuery macht. Andere Möglichkeiten sind z.B. $.get() und $.getJSON(), die für die speziellen Fälle GET-Request und GET-Request mit JSON-Resultat genutzt werden können. Mehr Informationen hierzu findet sich in der jQuery-Dokumentation.
Man sieht: jQuery macht einem Entwickler auch an dieser Stelle das Leben deutlich einfacher, indem es von den “plain vanilla”-Möglichkeiten von JavaScript abstrahiert und intern Cross-Browser-Kompatibilität sicherstellt. Es sollte daher neben den Standard-Patterns für die Erstellung wartbaren JavaScript-Codes in keinem Repertoire eines JavaScript-Entwicklers fehlen.