JavaScript Zeitproblem?

-=Renegade=-

Lt. Junior Grade
Registriert
Nov. 2006
Beiträge
427
Hallo!

Ich habe ein recht merkwürdiges Problem mit Ajax:

Aus Performancegründen wird ein Menü mit ca 7000 Datensätzen (ähnlich dem Windows Explorer aufgebaut) per Ajax aus einer Datenbank zusammengestellt. Dabei wird auf Klick immer nur die Ebene gelade, die gerade benötigt wird. Wenn die Ebene nicht mehr benötigt wird (zugeklappt) wird der Menüpunkt nicht gelöscht sondern nur versteckt, um mehrfaches Laden zu vermeiden.

Das Grundproblem war dann, wenn man einen Menüpunkt angeklickt hat und damit die Seite neu geladen hat, ist die ganze Struktur wieder zusammengeklappt worden (Standardmäßig ist keine Subebene geöffnet). Die Verwendung von iframes oder AJAX für die restliche Seite ist nicht oder nur sehr schwer möglich, da ich ein vorgegebenes Framework verwenden muss und dies massive Eingriffe in den Kern und die Struktur des Frameworks nach sich ziehen würde.

Deshalb wird, wenn eine Seite geladen wird, ein Script ausgeführt, das die einzelnen Menüpunkte bis zu diesem Unterpunkt lädt. (Code ist weiter unten, ich denke damit wird es verständlich)

Der Code den ich habe funktioniert an sich, ABER:
Es kommen immer wieder Fälle vor, in denen es nicht geht. Dies ist aber nicht abhängig von gewissen Menüpunkten sondern scheinbar rein "zufällig", das heißt, mal klappt der Menüpunkt richtig auf und manchmal nicht.

Gleich einmal vorweg: Meine Vermutung ist daher, das die zweite Funktion manchmal aufgerufen wird, bevor die erste fertig geladen wurde und daher den Fehler produziert. Eventuell benötigt man also einen Check, ob die Funktion in ihrer Auführung fertig ist? Aber dazu später mehr.

Die Fehlermeldung die Firebug dabei ausgibt sieht ca folgendermaßen aus:

Code:
GET http://tcweb/motdb/filebrowser.getdata.php?type=betriebe&parentid=1
200 OK     98ms      index....id=1548 (Zeile 159)

GET http://tcweb/motdb/filebrowser.getdata.php?type=kst&parentid=18
200 OK     118ms     index....id=1548 (Zeile 159)

GET http://tcweb/motdb/filebrowser.getdata.php?type=objekte&parentid=1800
200 OK     160ms     index....id=1548 (Zeile 159)

GET http://tcweb/motdb/filebrowser.getdata.php?type=aggregate&parentid=316
200 OK     129ms     index....id=1548 (Zeile 159)

document.getElementById(type + parentid) is null
[Break on this error] if(document.getElementById(type+parentid).innerHTML == "") {
index....id=1548 (Zeile 162)

In diesem Fall sind die ersten 4 Ebenen richtig dargestellt worden und erst bei der letzen gab es einen Fehler. Ein erneuter Durchlauf in der selben Hierarchie Struktur bringt zum Beispiel einen Fehler an folgender Stelle:

Code:
GET http://tcweb/motdb/filebrowser.getdata.php?type=betriebe&parentid=1
200 OK	83ms	index....id=1800 (Zeile 159)

GET http://tcweb/motdb/filebrowser.getdata.php?type=kst&parentid=18
200 OK	112ms	index....id=1800 (Zeile 159)

GET http://tcweb/motdb/filebrowser.getdata.php?type=objekte&parentid=1800
200 OK	102ms	index....id=1800 (Zeile 159)

document.getElementById(type + parentid) is null
[Break on this error] if(document.getElementById(type+parentid).innerHTML == "") {

Der Fehler kann also an jeder Stelle auftreten und kommt immer zufällig. In ca. 50% der Fälle kommt es zu keinem Fehler (der Wert ist natürlich viel zu niedrig um den Fehler zu ignorieren)

Der dazugehörige AJAX Code sieht wie folgt aus:

Code:
<script>
	function getdata(type, parentid, xmlhttp) {
		if (window.XMLHttpRequest) {
			xmlhttp = new XMLHttpRequest();
		} else if (window.ActiveXObject) {
			try {
				xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {
				try {
					xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
				} catch (E) {
					xmlhttp = false;
				}
			}
		}
		
		if (xmlhttp) {
			xmlhttp.open("GET", "filebrowser.getdata.php?type="+type+"&parentid="+parentid, true);
			xmlhttp.overrideMimeType("text/xml; charset=ISO-8859-1");
			xmlhttp.send(null);
			xmlhttp.onreadystatechange = function() {
				if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
					if(document.getElementById(type+parentid).innerHTML == "") {
						document.getElementById(type+parentid).innerHTML=xmlhttp.responseText;
						document.getElementById(type+parentid+"_img").src="images/symbol/minus.gif";
					}else{
						if(document.getElementById(type+parentid).style.display == "none") {
							document.getElementById(type+parentid).style.display="block";
							document.getElementById(type+parentid+"_img").src="images/symbol/minus.gif";						
						}else{
							document.getElementById(type+parentid).style.display="none";
							document.getElementById(type+parentid+"_img").src="images/symbol/plus.gif";
						}
					}
				}
			};
		}
	}
</script>

Der Script Code in den Dokumenten, der die Baumstruktur öffnet, sieht ungefähr so aus:

PHP:
$Script = "<script>getdata('betriebe','1'); getdata('kst','".$obj->BID."'); getdata('objekte','".$obj->KNR."'); getdata('aggregate','".$obj->OBJID."');</script>";

Ist das Dokument auf einer höheren Ebene, fallen die hinteren Funktionen dementsprechend weg.
Die mit PHP generierten ID Werte habe ich bereits überprüft, auch bei Fehlerfällen werden sie richtig generiert, d.h. die Parameter für die JS Funktion sind ansich immer korrekt vorhanden.

Der DIV Tag, also das Element, das angeblich null ist, existiert, wenn ich den Code danach mit Firebug untersuche.

Hier vermute ich trotz allem den Fehler, da die Funktionen sequentiell hintereinander aufgerufen werden. Kann es eventuell sein, das die nächste getdata Funktion aufgerufen wird, bevor die vorhergehende abgeschlossen wurde? Eventuell wenn der AJAX Request zulange dauert?

Bin wirklich am verzweifeln, da der Fehler wirklich zufällig ist und daher sehr schwer zu finden.

Bin für jede Hilfe dankbar!

so long
Renegade
 
Zuletzt bearbeitet:
Wenn ich das richtig sehe, führst du die "getdata" Methode sofort aus. Das kann aber dazu führen, dass sie ausgeführt wird, bevor alle DIVs im Browser geladen sind.
Du musst die "getdata" Methode erst aufrufen, wenn das Dokument fertig geladen hat. Glaub das geht mit der window.onload Methode oder so ähnlich (Ich benutze JQuery und da gibt es eine fertige Funktion dafür, daher weiss ich nicht, wie es in purem Javascript geht).
 
onload wird aber beim Laden der Datei ausgeführt und nicht wenn sie fertig geladen wurde, oder hab ich das falsch verstanden?

Praktisch wäre onload in divs :/ Oder ein Handler der ausgeführt wenn ein Element geladen wurde
 
Zuletzt bearbeitet:
onload wird aufgerufen, wenn das Dokument fertig geladen ist. Sind denn alle DIVs in der HTML Datei schon vorhanden oder werden die teilweise dynamisch erstellt?
 
Naja, das Problem ist eben, das mit jedem getdata() neue DIVs generiert werden, auf die der nächste getdata() Aufruf aufbaut. Das heißt, mit getdata() hangelt er sich Ebene für Ebene nach unten in der Verzeichnis Struktur.
 
OK, jetzt verstehe ich das. Ja, ich denke auch, dass hier ein späterer Request fertig ist, bevor der frühere fertig ist und daher die DIVs noch nicht existieren. Man sieht ja auch in deinen Firebug Logs, dass der Fehler immer dann kommt, wenn die Zeitangaben kleiner werden (98ms, 118ms, 160ms, 119ms, Fehler).

Musst du am Besten in der getdata Methode prüfen, ob schon ein Request läuft; und falls ja, dann speicherst du den nächsten auszuführenden Request in ein Array. Wenn dann der erste Request fertig ist, schaust du im Array nach, ob dort Requests drinstehen und führst diese aus.
 
Inwiefern soll ich das prüfen? Ich kann ja auf keine Variablen oder so direkt während des Ajax Requests zugreifen... aber ich könnte danach was setzen... werd mir das mal ansehen.

Hab jetzt bei Bedarf ein 250ms Timeout gesetzt, wenn das benötigte Element nicht existiert, damit hab ich die Fehlerrate auf <5% gesenkt
 
So irgendwie in der Art würd ichs machen. Ist jedoch ungetestet:
Code:
// für alle zukünftig auszuführenden Aufrufe
var futureRequests = [];
// ob grade ein getdata Vorgang läuft
var requestInProgress = false;



function getdata(type, parentid, xmlhttp) {

    // falls bereits ein request läuft, dann den neuen im array speichern für später
    if(requestInProgress)
    {
        futureRequests.push([type,parentid,xmlhttp]);
    }
    else
    {
        requestInProgress = true;
        
        
        if (window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
        } else if (window.ActiveXObject) {
            try {
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            } catch (e) {
                try {
                    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
                } catch (E) {
                    xmlhttp = false;
                }
            }
        }
        
        if (xmlhttp) {
            xmlhttp.open("GET", "filebrowser.getdata.php?type="+type+"&parentid="+parentid, true);
            xmlhttp.overrideMimeType("text/xml; charset=ISO-8859-1");
            xmlhttp.send(null);
            xmlhttp.onreadystatechange = function() {
                if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                    if(document.getElementById(type+parentid).innerHTML == "") {
                        document.getElementById(type+parentid).innerHTML=xmlhttp.responseText;
                        document.getElementById(type+parentid+"_img").src="images/symbol/minus.gif";
                    }else{
                        if(document.getElementById(type+parentid).style.display == "none") {
                            document.getElementById(type+parentid).style.display="block";
                            document.getElementById(type+parentid+"_img").src="images/symbol/minus.gif";						
                        }else{
                            document.getElementById(type+parentid).style.display="none";
                            document.getElementById(type+parentid+"_img").src="images/symbol/plus.gif";
                        }
                        
                        
                        // schauen ob noch requests ausgeführt werden sollen
                        requestInProgress = false;
                        if(futureRequests,length>0)
                        {
                            var f = futureRequests.shift();
                            getdata(f[0],f[1],f[2]);
                        }    
                    }
                }
            };
        }
    }
}
 
Zurück
Oben