Callback-Funktionen
Viele Funktionen der PTraffic-Bibliothek sind sogenannte Callback-Funktionen. Dies bedeut das der PTraffic-Funktion eine Funktion als Parameter übergeben wird die für die weitere Ausführung nach dem Abarbeiten der PTraffic-Funktion zuständig ist.Um mit diesen Callback-Funktionen zu arbeiten sind einige Dinge zu beachten die nachfolgend erläutert werden.
Technischer Hintergrund
Die verwendete Javascript-Bibliothek PublicSQL ermöglicht SQL-Abfragen direkt in Javascript. Die Tabellen – standardmäßig erkennbar an der Endung “.ptf” - müssen dazu nicht in die HTML-Datei eingebunden werden sondern werden beim Aufruf der SQL-Anweisungen nachträglich in die HTML-Datei eingebunden.
Da HTML und Javascript standardmäßig kein Nachladen von Dateien unterstützen wird hierzu ein Trick angewandt: Die PTF-Dateien sind eigentlich Javascript-Dateien in denen die Daten als Array gespeichert sind. Wird nun eine SQL-Abfrage durchgeführt werden alle benötigten und noch nicht geladenen Dateien nachträglich in den Dateikopf zwischen <head>. und </head>) eingebunden. Die neue Zeile sieht beispielsweise so aus:
<script src="ptf/stations.ptf?x=-156450406" type="text/javascript"></script>
Wie man sieht hat die PTF-Datei – die ja wie gesagt eine Javascript-Datei ist – einen Parameter (x=-156450406). Dieser Parameter wird aus dem aktuellen Datum und der Zeit errechnet. Dadurch wird verhindert, dass die Datei – soweit vorhanden - aus dem Cache (Zwischenspeicher) verwendet wird: Bei jeden Aufruf wird ein anderer Wert angehängt und die Datei wird nicht als gleiche Datei behandelt und daher neu geladen.
Anschließend wird dem neuen <script>-Tag ein onload-Event-Handler hinzugefügt, der aufgerufen wird sobald die Datei (im Beispiel "stations.ptf") vollständig geladen ist. In diesem Event-Handler wird zum Schluss die übergebene Callback-Funktion aufgerufen. Dadurch ist sichergestellt dass beim Aufruf der Callback-Funktion die Daten der PTF-Datei vollständig geladen und in PublicSQL eingebunden sind.
Würde man keine Callback-Funktion verwenden sondern einfach nach Ausführung der SQL-Anweisung versuchen das Ergebnis der Abfrage zu verwenden, würde dies zu Fehlern führen da das Ergebnis noch nicht zur Verfügung steht.
Der Vorteil der Callback-Funktionen besteht darin, dass ein Nachladen einzelner Dateien möglich ist. Möchte man beispielsweise einen Fahrplan ausgeben werden nur die Dateien für die gewählte Linie, Richtung sowie für den gewählten Wochentag geladen. Ansonsten müßte man bereits vorher sämtliche Fahrplandateien laden. Bei 10 Linien mit 3 Wochentag-Gruppen (Mo-Fr, Sa, So) und 2 Richtungen wären das beispielsweise 70 PTF-Dateien.
Auswirkungen
Beachtet man die Besonderheiten der Callback-Funktion nicht kann dies zu seltsamen Fehlern führen.
Im folgenden Beispiel werden 2 PublicSQL-Anweisungen direkt hintereinander aufgerufen.
<div id="testdiv">
</div>
<div id="names">
<b>Stations-Namen:<br></b>
</div>
<div id="ids">
<b>Stations-ID's:<br></b>
</div>
<script>
function cbfunc1(t) {
document.getElementById('names').innerHTML += "<br>" + t;
}
function cbfunc2(t) {
document.getElementById('ids').innerHTML += "<br>" + t;
}
publicSQL.tablePath = "ptf/"; // Pfad für PTF-Dateien
publicSQL.setTableCache(false); // Table-Cache ausschalten
publicSQL.query("select Station from stations order by Station", "cbfunc1");
publicSQL.query("select ID from stations order by ID", "cbfunc2");
</script>
Nach Ausführung der publicSQL.query-Anweisungen werden im <head>-Bereich der HTML-Seite gleich 2 <script>-Anweisungen eingefügt:
<head> … <script src="ptf/stations.ptf?x=-156529607" type="text/javascript"></script> <script src="ptf/stations.ptf?x=-156529607" type="text/javascript"></script> </head>
Dies liegt daran, dass beim 2. Aufruf von publicSQLquery der 1. Aufruf noch nicht abgearbeitet wurde. Beim 2. Aufruf von PublicSQL.query ist die Datei “stations.ptf” noch nicht geladen und die Funktion cbfunc1 wurde ebenfalls noch nicht ausgeführt.
Der Umgang mit Callback-Funktionen erfordert also eine andere Vorgehensweise.
Umgang von Callback-Funktionen bei Nutzung der PTraffic-Library
Zur Vermeidung von Fehlern bei der Verwendung von Callback-Funktionen wird folgende Vorgehensweise empfohlen:
1. Wenn eine PTraffic- oder PublicSQL-Funktion aufgerufen wird, die eine Callback-Funktion als Parameter erfordert, sollte der Quelltext an dieser Stelle beendet werden. Alle weiteren Anweisungen werden dann in der Callback-Funktion geschrieben.
2. Sollen mehrere Funktionen mit übergebeneer Callback-Funktion nacheinander aufgerufen werden wird jeder Aufruf in einer eigenen Funktion geschrieben. Statt
Funktion1(..., "callback_func1") ... // diverse Anweisungen nach Aufruf von Funktion1 ... Funktion2(..., "callback_func2") ... // diverse Anweisungen nach Aufruf von Funktion2 ... Funktion3(..., "callback_func3") ... // diverse Anweisungen nach Aufruf von Funktion3 ... // letzte Anweisung
sieht der Quelltext dann folgendermaßen aus:
function callback_func3 {
...
// diverse Anweisungen nach Aufruf von Funktion3
...
// letzte Anweisung
}
function callback_func2 {
...
// diverse Anweisungen nach Aufruf von Funktion2
...
Funktion3(..., "callback_func3")
}
function callback_func1 {
...
// diverse Anweisungen nach Aufruf von Funktion1
...
Funktion2(..., "callback_func2")
}
Funktion1(..., "callback_func1")
Es gibt noch eine weitere Methode zum Umgang mit aufeinanderfolgenden Callback-Funktionen die etwas komplizierter zu handhaben ist. Diese kann man sich in der PTraffic-Library beispielsweise bei der Funktion ptInit() anschauen. Der Vorteil dieser Methode besteht darin dass der gesamte Quelltext, durch Verwendung von Unterfunktionen, in einer einzigen Funktion geschrieben werden kann.
3. Für eine bessere Übersicht ist es empfehlenswert für alle zusammenhängenden Callback-Funktionen identische Namen mit fortlaufender Nummerierung zu verwenden. Im Beispiel wurde der Name “callback_func” mit fortlaufender Nummerierung verwendet. Durch die Namensgleichheit ist später sofort erkennbar welche Funktionen logisch zusammengehören.
Ob diese Funktionen in der oben verwendeten Reihenfolge (die erste Funktion “callback_func1” steht an letzter Stelle) oder in umgekehrte Reihenfolger (die erste Funktion steht an erster Stelle) stehen ist für die Funktionalität nicht relevant. Man sollte jedoch der Übersicht halber die Reihenfolge der Funktinosaufrufe innerhalb der Callback-Funktions-Blöcke immer gleich behandeln.
4. Am einfachsten ist es wenn man die HTML-Datei so aufbaut, dass Aufrufe von Funktionen mit übergebener Callback-Funktion nur im onload-event-handler (z. B.: <body onload=”initFunc()”>) sowie in anderen Eventhändlern für Buttons, Eingabefeldern etc. stattfinden.
Da man – z. B. mit der Funktion document.getElementById – auf alle Elemente der HTML-Datei zugreifen kann und diese auch ändern bzw. erweitern kann, ist ein Aufruf der Funktionen mit Callback-Funktions-Parameter beim Aufbau der HTML-Datei (also vor dem onload-Event) normalerweise nicht nötig.
Da in der PTraffic-Bibliothek als erstes die Funktion ptInit() aufgerufen werden muss und diese auch eine Funktion mit Callback-Funktions-Parameter ist sollte diese im onload-event aufgerufen werden. Gegebenenfalls können dann weitere Funktionen wie oben beschrieben hinzugefügt werden.
5. Die Javascript-Funktion document.write(...) sollte grundsätzlich – nicht nur bei Verwendung von Callback-Funktionen – nur beim Aufbau der Seite verwendet werden. Sobald die Seite geladen ist sollte die Funktion nicht mehr verwendet werden. Neue Elemente (Texte, HTML-Befehle etc.) können ggfs. mit Javascript-Funktionen wie createTextnode() , createElement() und createAttribute() nachträglich hinzugefügt werden.
Unterschied bei Callback-Funktionen zwischen PublicSQL und der PTraffic-Bibliothek
In der PTraffic-Bibliothek wird der Name der Callback-Funktion direkt als Funktionsparameter übergeben. In PublicSQL wird der Name der Callback-Funktion als String übergeben.
Beispiele:
PTraffic: ptInit("Pro", "ptf", CallBackFunktion);
PublicSQL: publicSQL.query("select * from stations", "CallBackFunktion");