Rüdiger
unread,May 5, 2010, 5:50:12 AM5/5/10Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to BSP-Praxis
Wie beschafft man sich in einer HTML-Seite, ohne diese Seite zu
verlassen, den Inhalt eines auf dem Server gelagerten Files?
Normalerweise würde ich hierfür einen Ajax.Request() verwenden. Das
ist einfach und funktioniert auf Anhieb. Leider aber nicht für lokale
URL's unter Windows. Da dies für mich eine Einschränkung war (ich habe
eine lokale ECMAUnit-Testseite, die ich beim lokalen Entwickeln
mittels "Aktualisieren" immer wieder starten will), bin ich auf die
gute alte <iframe>-Technik zurückgekommen:
Man versteckt dazu einen <iframe id="loader" style="display:none"
src="blank.txt"/> in der Seite und setzt auf Anforderung das src-
Attribut auf einen anderen Wert. Der iframe lädt dann die angegebene
Datei vom Server in seinen Content. In meinem Fall waren das Textfiles
mit JSON-Daten für die weitere Verarbeitung in der Webseite.
Nun gibt es hier eine Verzögerung. Die Zuweisung $("loader").src =
"meinFile.txt" wartet nicht, bis "meinFile.txt" wirklich im <iframe>
angekommen ist, sondern die Verarbeitung wird einfach fortgesetzt.
Hier wäre man versucht, nach einer wait()-Funktion in JavaScript zu
suchen oder ggf. eine zu schreiben. Man kann solche Funktionen
schreiben, und man findet im Web auch solche Funktionen, aber sie sind
grauenhaft. Meist werden in einer while-Schleife neue Date-Objekte
instanziiert, bis der Wait-Timeout erreicht ist. Das wird die CPU-
Statuslampe auf Rot bringen. Die Millionen neuen Date-Objekte müssen
laufend via garbage collection entsorgt werden. Vor allem aber reisst
das JavaScript den Kontrollfluss an sich, nur weil Programmierer es
gewohnt sind, ein Programm nicht anders als linear zu denken.
JavaScript wurde als Sprache entwickelt, die auf dem DOM operieren
soll. DOM ist ein *ereignisbasiertes* Objektmodell. Extra deshalb gibt
es in JavaScript die schönen Closures, also Funktionsreferenzen, die
sich den lokalen Ausführungskontext merken. Statt in der Form
: Anweisung n ist beendet. Nun führe Anweisung n+1 aus
zu denken, denkt man in ereignisbasierter Programmierung so:
: Starte Operation x. Registriere Funktion f für das Ereignis
"Operation x beendet"
Das ist viel ressourcenfreundlicher und bildet obendrein die
Abhängigkeiten der Programmteile klarer ab. Denn bevor die Operation x
beendet ist, gibt es keine Notwendigkeit, irgendeinen JavaScript-
Befehl auszuführen, der die Operation x voraussetzt. In der
Zwischenzeit kann das System aber sinnvollere Dinge machen als in
einer Endlos-Schleife Date()-Objekte zu produzieren. Ereignisbasiert
programmieren bedeutet: Nicht immer die ganze Kontrolle an sich
reissen, sondern relaxed bleiben. Man kann auch mal loslassen. :-)
In meinem Fall habe ich die Erwartung fallengelassen, eine Funktion
readFile zu schreiben, die etwa folgendermassen funktionieren könnte:
var text = readFile( "meinFile.txt" );
macheEtwasMit( text );
Das ist zu prozedural gedacht. Eine Funktion readFile habe ich zwar
nun doch, aber sie funktioniert anders. Sie nimmt neben dem Filenamen
auch noch eine Funktionsreferenz entgegen: Den Behandler, der nach dem
Einlesen des Files ausgeführt werden soll.
function readFile( fileName, followupFunction ) {
var doOnIframeLoaded = function() {
var text = top.loader.document.body.innerText ||
top.loader.document.body.textContent;
followupFunction( text );
};
$("loader").stopObserving("load");
$("loader").src = fileName;
$("loader").observe( "load", doOnIframeLoaded );
}
Wie man sieht, habe ich den Aufruf der followupFunction, die vom
Aufrufer übergeben wird, noch in eine lokale Closure eingepackt, die
als Adapter fungiert. Diese Closure und nicht die übergebene Funktion
ist als EventHandler für das onload-Ereignis des <iframe> registriert.
Sie ruft dann die Funktion mit dem gelesenen Text auf. Das ist einfach
eine Indirektion: Dem Aufrufer ist es ja egal, wie die readFile()-
Funktion implementiert ist: ob mit Ajax oder einem iframe oder wie
auch immer. Der Aufrufer legt nur fest, was mit dem gelesenen Text
dann gemacht werden soll. Wenn ich also einmal eine andere
Implementierung für readFile() wählen würde, wird an den followUp-
Funktionen nichts geändert werden müssen.
Aber es ist natürlich schön zu sehen, dass selbst die followUp-
Funktion in der Closure aufbewahrt wird, die ja durchaus selbst auch
wieder eine Closure sein kann: Alle benötigten lokalen Kontexte sind
vefügbar. Diese Technik ist wie geschaffen für ereignisbasiertes
Programmieren.