Tagesarchiv: 13.8.2006

Asynchrones JavaScript ohne «AJAX»

Vor einigen Jahren tauchte im Umfeld des Webdesigns der Begriff «DHTML» auf, einer Technik die das Verändern einer Webseite ermöglicht, ohne dabei eine neue Anforderung an den Server zu senden. Nun war DHTML weder eine HTML-Erweiterung, noch eine neue Programmiersprache. DHTML war lediglich der Sammelbegriff einiger Techniken und Methoden. Und sie alle verwendeten bestehende und bestens etablierte Standards: HTML, CSS und JavaScript/DOM.

Mit «AJAX» verhält es sich sehr ähnlich. AJAX nutzt mehrere etablierte Techniken um den Inhalt einer Seite basierend auf Daten zu verändern, die nach dem Ladeprozess vom Server geholt werden. Daher auch der Begriff «asynchron». In der Praxis sieht das so aus, dass der Benutzer im Browser eine Adresse eingibt und damit die zu dieser Adresse gehörende Webseite öffnet. Verwendet die Seite AJAX-Techniken, können durch Benutzerinteraktion jederzeit im Hintergrund Daten vom Server nachgeladen werden, der Inhalt einer Tabelle zum Beispiel.

Um asynchrone Webseiten selbst zu erstellen, ist es nicht zwingend erforderlich, auf eine AJAX-Bibliothek zurückzugreifen, es genügt, die Elemente zu verwenden, die JavaScript mit asynchronen Funktionen erweitern. Im wesentlichen ist dies das XMLHttpRequest -Objekt, das in allen neueren Browsern zu finden ist. Seine Funktionsweise ist sehr einfach: nachdem mit open() eine zu ladende Adresse angegeben wurde, kann die Anforderung mit send() zum Server gesandt werden. Einige weitere Funktionen und Attribute informieren über den Fortschritt des Ladeprozesses und darüber, ob die Operation erfolgreich war, oder nicht. Die folgende, kurze JavaScript Funktion nimmt als Argument eine URL entgegen und liefert als Ergebnis den Inhalt dieser URL:

function getURLContent(url) {
  var xmlHttp = false;
  var urlcontent = '';

  // Mozilla, Opera, Safari sowie Internet Explorer 7
  if (typeof XMLHttpRequest != 'undefined') {
    xmlHttp = new XMLHttpRequest();
  }
  if (!xmlHttp) {
    // Internet Explorer 6 und aelter
    try {
      xmlHttp  = new ActiveXObject("Msxml2.XMLHTTP");
    } catch(e) {
      try {
        xmlHttp  = new ActiveXObject("Microsoft.XMLHTTP");
      } catch(e) {
        xmlHttp  = false;
      }
    }
  }
  if (xmlHttp) {
    // Synchrones Lesen einer URL
    xmlHttp.open('GET', url, false);
    xmlHttp.send(null);
    if (xmlHttp.status == 200) {
      urlcontent = xmlHttp.responseText;
    }
  }
  return(urlcontent);
}

Im ersten Teil der Funktion wird eine neue Instanz des XMLHttpRequest Objektes erzeugt. Ältere Versionen des IE erfordern eine leicht abweichende Syntax, deshalb wurde eine entsprechende Prüfung eingebaut, damit wir auf jeden Fall eine Instanz erhalten. Anschliessend wird mittels open() und send() eine Anforderung (GET, POST, HEAD) an den Server gesendet. open() legt die Adresse, die HTTP-Methode und den Asynchronmodus fest. send() sendet dann die Anforderung an den Server. Wichtig ist im folgenden der mittels open()festgelegte Asynchronmodus (AM). Wird für AM TRUE angegeben, wartet send() nicht bis das Eregbnis vorliegt, dieses muss mit Hilfe einer Callbackfunktion ermittelt werden. Bei AM=FALSE wartet send() solange, bis der Server das Ergebnis übermittelt hat. Mein Beispiel verwendet einfachheitshalber AM=FALSE.

Es ist nun nicht mehr Schwierig, eine Funktion zu schreiben, die mit Hilfe der beschriebenen Funktion einen in PHP oder PERL geschriebenen Serverscript aufruft und dessen Ergebnis an einer passenden Stelle auf der Webseite präsentiert. Wer in vorgegebenen Intervallen Daten vom Server holen will, kann setInterval() oder setTimeout verwenden. Wie die Daten anschliessend in die Webseite eingesetzt werden, kann bei SelfHTML nachgelesen werden.

Dies alles zusammengepackt auf einer schön gestalteten Webseite lässt bereits einen «Hauch von AJAX» aufkommen.

Update 16.8.2006: Probleme

Ein Problem, das im Internet immer wieder diskutiert wird, ist das Caching. Während Opera das Zwischenspeichern von xmlHTTPRequest Anfragem relativ leicht abgewöhnt werden kann, macht der Internet Explorer erfahrungsgemäss deutlich mehr Schwierigkeiten. Eine Suche in der Foren fördert einen Workaround zutage, der auch beim IE immer Wirkung zeigt: Der gewünschten URL wird bei jedem Aufruf eine Zufallszahl angehängt, also zum Beispiel:

  var rnd = parseInt(Math.random()*99999999);
  var url = 'example.php?random=' + rnd;
  var  content = getURLContent(url);

Damit wird verhindert, dass der aggressive Caching Algorithmus des IE greift: Da die Adresse jedesmal anders ist, muss der Redmond-Browser sie neu vom Server abholen. Natürlich ist dies eine Holzhammer-Methode, ich habe deshalb versucht, das Problem mit HTTP Head Anweisungen für alle Browser zu lösen. Der folgende PHP-Script wird von allen aktuellen Browser beim jedem Aufruf neu abgeholt:

< ?php
  header("Pragma: no-cache");
  header("Cache-Control: no-cache");
  header("If-Modified-Since: 1980-01-01");
  print "Inhalt der Seite";
?>

25 Jahre IBM PC

Gestern Samstag gab es ein Jubiläum zu feiern: Am 12. August 1981, also vor 25 Jahren, stellte IBM in New York der Öffentlichkeit den ersten Personal Computer (PC) vor. Niemand hat damals geahnt, dass dies zugleich der Startschuss für eine Revolution in der Computerbranche war. Innerhalb weniger Jahre entstand ein grosser, weltumspannender Markt für Hard- und Software rund um den PC. Der PC verdrängte die damals populären Homecomputer von Commodore, Texas Instruments und Atari. Und er verdrängte die Computer mit dem bunten Apfel-Logo, so dass Apple das Frotzeln («Welcome, IBM») über den vermeintlich trägen Grosskonzern verging. Der Erfolg rief natürlich Nachahmer auf den Plan und noch bevor IBM die ersten Nachfolger lancieren konnte, erschienen auf dem Markt «Klone», also Computer, die zum IBM PC kompatibel waren.

Warum war der IBM PC so erfolgreich? Er kam zur richtigen Zeit! Kleinere Unternehmen konnten sich keine teuren Zentralrechner («Hosts») leisten und die verfügbaren Homecomputer waren wenig zuverlässig, untereinander nicht kompatibel und für die geforderte Aufgabenstellung nicht leistungsstark genug. Da kam der preiswerte Bürocomputer aus dem Hause IBM gerade recht.

Aber dies alleine erklärt das Phänomen «PC» nicht. Ein wesentlich bedeutender Grund liegt in der Technik des IBM PC. Denn dieser bestand vorwiegend nicht aus Komponenten des Herstellers, sondern aus Elektronikbauteilen, die IBM zusammengekauft hat. Dazu – und das war bei IBM neu – waren diese Bauteile für Programmierer und für Hersteller von Zusatzkomponenten offen dokumentiert. Der PC verfügte über sogenannte «Slots», das sind Steckplätze für Platinen die den Funktionsumfang des PC erweitern: Netzwerkadapter, Grafikkarten, Schnittstellen für Geräte anderer Hersteller, usw. Kurz: Jeder, der für den PC eigene Produkte entwickeln wollte, konnte dies ungehindert tun! Dies war der Beginn einer Eigendynamik, die bis heute ungebrochen ist, denn wesentliche Konzepte des IBM PC finden sich auch noch in den Geräten der Gegenwart.

Einen IBM PC konnte ich mir in den frühen 80’Jahren nicht leisten. Als aber Commodore wenige Jahre später einen günstigen PC lancierte, griff ich zu und kaufte für ca. Fr. 3200.- einen Commodore PC 10. Er besass wie das Vorbild einen mit 4.77Mhz getakteten Intel 8088, zwei 5 1/4 Zoll Diskettenlaufwerke, 256 KB RAM und einen nicht grafikfähigen Monochrombildschirm. Mitgeliefert wurde eine MS-DOS Diskette. Mehr nicht. Was konnte ein Hobby-Programierer damit anfangen? Zunächst nicht viel!

Um eigene Programme zu schreiben – und nur dafür schien mit der PC interessant – gab es nur GW BASIC. Zwar gab es C Compiler, aber die waren kompliziert, quälend langsam und zu teuer. Also schrieb nich meine ersten Programme in GW BASIC: Einfachere Spiele, ein Ranglistenprogramm für Radrennen, eine Karteianwendung, ein KI-Proramm und einiges mehr. Aber, um ehrlich zu sein, es machte überhaupt keinen Spass. Die BASIC-Programme waren langsam und konnten nicht kompiliert werden. Es gab keine Elemente zur strukturierten Programmierung und dass jeder Anweisung eine Zeilennummer vorangestellt werden musste, nervte total!

Ein Lichtblick war kurz darauf ein kleines Programm, das den Bildschirmadapter in einen Quasi-Grafikmodus versetzen konnte. Mit Hilfe eines weiteren Treibers wurde GW-BASIC um einige grundlegende Grafikbefehle erweitert, so dass auf dem Bildschirm Linien und einfache geometrische Figuren gezeichnet werden konnten. Das erstellen eines Spieles in diesem Modus schlug indes fehl weil – wie gesagt – GW-BASIC zu langsam war!

Und dann geschah plötzlich etwas wunderbares: Turbo Pascal für den PC erschien und erlöste Hobbyprogrammierer wie professionelle Entwickler von GW-BASIC. Turbo Pascal war einfach zu bedienen, übersetzte die Programme rasend schnell in effizienten Maschinencode, half dem Entwickler mit aussagekräftigen Fehlermeldungen und einem komfortablen Editor. Pascal erlaubte strukturiertes Programmieren mit Anweisungsblöcken, Funktionen und Prozeduren und noch vielen Leckerbissen mehr. Bei grösseren Projekten konnten die Programme sogar in verschiedene Dateien ausgelagert werden und wenn sie die 64KB Grenze sprengten, behalf mach sich mir Overlays.