• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

[FRAGE] Registrierung einer Funktion, welche nach dem load Event laufen soll

Joller

New member
Hallo,

im Buch "JavaScript: The Definitive Guide“ wird folgender Code dargestellt (Example 13-5. onLoad(): invoke a function when the document loads):
Code:
// Register the function f to run when the document finishes loading.
// If the document has already loaded, run it asynchronously ASAP.
function onLoad(f) {
   if (onLoad.loaded) // If document is already loaded
      window.setTimeout(f, 0); // Queue f to be run as soon as possible
   else if (window.addEventListener) // Standard event registration method
      window.addEventListener("load", f, false);
   else if (window.attachEvent) // IE8 and earlier use this instead
      window.attachEvent("onload", f);
}
// Start by setting a flag that indicates that the document is not loaded yet.
onLoad.loaded = false;
// And register a function to set the flag when the document does load.
onLoad(function() { onLoad.loaded = true; });
Frage 1

Der Ablauf des Codes ist mir nicht ganz klar: Während das Dokument lädt, wird der JavaScript-Code ausgeführt („first phase“ S. 317). Damit wird onLoad.loaded = false gesetzt und anschließend die Funktion onLoad ausgeführt, wobei die (anonyme) Funktion übergeben wird. An dieser Stelle ist onLoad.loaded auf jeden Fall false. Damit wird zunächst ein EventListener registriert/attached. Wenn das Dokument dann geladen ist („load“ - Event), wird die (anonyme) Funktion erstmalig ausgeführt und onLoad.loaded = true gesetzt. Die Funktion setTimeout() wird doch dann aber gar nie ausgeführt!?

Frage 2

Es könnte zudem sein, dass das Dokument bei Ausführung des Codes bereits fertig geladen ist. Dann wird auch hier onLoad.loaded = false gesetzt und durch die Funktion onLoad ein EventListener registriert/attached. Da es jedoch keinen weiteren load Event mehr gibt, wird die (anonyme) Funktion gar nie ausgeführt. Sehe ich das richtig? Falls nein, wie läuft der Code ab?

Frage 3

Wird mit onLoad.loaded = false; eine Variable innerhalb der Funktion onLoad erstellt (dann aber müsste man in der Funktion onLoad nicht onLoad.loaded schreiben, sondern nur loaded) oder wird im globalen Objekt ein neues Objekt onLoad angelegt (mit demselben Namen wie die Funktion onLoad - das ginge aber wohl auch nicht) mit einem Property loaded?

Gruß,

Joller
 
Frage 1

Der Ablauf des Codes ist mir nicht ganz klar: Während das Dokument lädt, wird der JavaScript-Code ausgeführt („first phase“ S. 317). Damit wird onLoad.loaded = false gesetzt und anschließend die Funktion onLoad ausgeführt, wobei die (anonyme) Funktion übergeben wird. An dieser Stelle ist onLoad.loaded auf jeden Fall false. Damit wird zunächst ein EventListener registriert/attached. Wenn das Dokument dann geladen ist („load“ - Event), wird die (anonyme) Funktion erstmalig ausgeführt und onLoad.loaded = true gesetzt. Die Funktion setTimeout() wird doch dann aber gar nie ausgeführt!?
Ja... und was ist jetzt deine Frage?

Frage 2

Es könnte zudem sein, dass das Dokument bei Ausführung des Codes bereits fertig geladen ist. Dann wird auch hier onLoad.loaded = false gesetzt und durch die Funktion onLoad ein EventListener registriert/attached. Da es jedoch keinen weiteren load Event mehr gibt, wird die (anonyme) Funktion gar nie ausgeführt. Sehe ich das richtig? Falls nein, wie läuft der Code ab?
Nein, wenn der Code über normale <script>-Tags eingebunden ist, kann das Dokument noch nicht fertig geladen sein.
Frage 3

Wird mit onLoad.loaded = false; eine Variable innerhalb der Funktion onLoad erstellt (dann aber müsste man in der Funktion onLoad nicht onLoad.loaded schreiben, sondern nur loaded) oder wird im globalen Objekt ein neues Objekt onLoad angelegt (mit demselben Namen wie die Funktion onLoad - das ginge aber wohl auch nicht) mit einem Property loaded?
onLoad.loaded ist einfach eine Eigenschaft des Objektes onLoad... in JS ist alles ein Objekt - auch Funktionen.
 
Ja... und was ist jetzt deine Frage?
Da es Code aus einem Buch in der 6. Auflage ist, gehe ich davon aus, dass folgender Code in irgendeinem Fall auch ausgeführt werden könnte. Da ich den Code bislang aber nicht ganz verstanden hatte, wollte ich wissen, ob es einen solchen Fall gibt, in dem er ausgeführt werden könnte.
Code:
if (onLoad.loaded)
      window.setTimeout(f, 0);

Nein, wenn der Code über normale <script>-Tags eingebunden ist, kann das Dokument noch nicht fertig geladen sein.

Danke.

onLoad.loaded ist einfach eine Eigenschaft des Objektes onLoad... in JS ist alles ein Objekt - auch Funktionen.

Danke. Habe versucht, in der Funktion anstelle von "if (onLoad.loaded)" folgendes zu verwenden: "if (loaded)", denn loaded ist ja dann eine Eigenschaft des Objekts (hier der Funktion) onLoad. Das geht aber nicht: "ReferenceError: loaded is not defined - if (loaded) {". Warum nicht?

Was ginge, wäre entweder "if (this.loaded)" oder loaded explizit zuvor "var loaded = false" innerhalb der Funktion deklarieren.
 
Da es Code aus einem Buch in der 6. Auflage ist, gehe ich davon aus, dass folgender Code in irgendeinem Fall auch ausgeführt werden könnte. Da ich den Code bislang aber nicht ganz verstanden hatte, wollte ich wissen, ob es einen solchen Fall gibt, in dem er ausgeführt werden könnte.
Ja, es gibt Fälle, in denen er ausgeführt wird. Das kann passieren, wenn du die Funktion onLoad() irgendwo anders in deinem Code aufgerufst, der z.B. erst später dynamisch dazugeladen wurde. Dann kann es sein, dass window.onload schon gefeuert hat und onLoad.loaded schon auf true gesetzt wurde.

Danke. Habe versucht, in der Funktion anstelle von "if (onLoad.loaded)" folgendes zu verwenden: "if (loaded)", denn loaded ist ja dann eine Eigenschaft des Objekts (hier der Funktion) onLoad. Das geht aber nicht: "ReferenceError: loaded is not defined - if (loaded) {". Warum nicht?
Weil JavaScript nicht Java ist und Eigenschaften irgendeines Objektes (normalerweise) nicht in den Variablenscope integriert werden.

Was ginge, wäre entweder "if (this.loaded)" oder loaded explizit zuvor "var loaded = false" innerhalb der Funktion deklarieren.
Nein, das würde auch beides nicht gehen, da this nicht das Funktionsobjekt ist, sondern der Aufrufkontext. Und eine lokalen Variable kann man nur über eine Closure persistent machen, so dass der Wert über die verschiedenen Funktionsaufrufe auch gespeichert bleibt.
 
Sorry, ich hoffe, ich darf noch einmal nachhaken.

Nein, das würde auch beides nicht gehen, da this nicht das Funktionsobjekt ist, sondern der Aufrufkontext. Und eine lokalen Variable kann man nur über eine Closure persistent machen, so dass der Wert über die verschiedenen Funktionsaufrufe auch gespeichert bleibt.
Ich hatte es schon vor meinem Eintrag ausprobiert - es geht. Also innerhalb der Funktion "if (onLoad.loaded)" ersetzen entweder durch "if (this.loaded)" oder durch "var loaded = false; if (loaded)". Letzteres macht natürlich vom Ablauf her keinen Sinn. Bei ersterem macht es jedoch keinen Unterschied, ob außerhalb der Funktion "loaded=false" oder "onLoad.loaded=false" definiert ist. Das ist das Wirre daran. Was wird mit "onLoad.loaded = false" definiert? Der invocation context der Funktion onLoad ist das globale Objekt. In folgendem Code wird mit loaded = false eine globale Variable definiert, welche dann in der Funktion mit if(this.loaded) abgefragt wird.
Code:
function onLoad(f) {
   if (this.loaded)             <== Abfragen der globalen Variablen "loaded", Definition weiter unten
      window.setTimeout(f, 0);
   else if (window.addEventListener)
      window.addEventListener("load", f, false);
   else if (window.attachEvent)
      window.attachEvent("onload", f);
}
loaded = false;        <== hier wird die globale Variable definiert. Doch es könnte auch onLoad.loaded=false stehen, es würde immer noch laufen, doch was wäre damit definiert?
onLoad(function() { onLoad.loaded = true; });
Was aber wäre mit "onLoad.loaded=false" definiert? Du schreibst, das die Eigenschaften irgendeines Objekts nicht in den variable scope integriert werden. Das verstehe ich. Doch bei "onLoad.loaded=false" bezieht sich das "onLoad" doch auf die Funktion "onLoad" und ist damit nicht irgendein Objekt!?

Ich lese "onLoad.loaded = false;" als: die Eigenschaft "loaded" des Objekts "onLoad" soll den Wert "false" haben. Dabei bezieht sich onLoad auf die Funktion mit demselben Namen, welche zuvor definiert wurde. Ersetzt man z.B. onLoad in dieser Deklaration durch einen anderen Namen, wird ein Fehler geworfen ("ReferenceError: myLoaded is not defined"). Wenn es sich also auf die Funktion bezieht, die ja letztlich auch ein Objekt ist, dann müsste die Eigenschaft loaded ja im variable scope enthalten sein.
 
Ja, es funktioniert, solange du nicht im Strict-Mode arbeitest (was ich dringend empfehle).

Mit "this.loaded" funktioniert das auch, wenn du keine globale Variable vorher definiert hast, da JS dann einfach sagt: ich kenne kein "loaded" im Objekt "this" - also geb' ich mal undefined zurück. Das wird aber im if als false interpretiert.

Das Funktionsobjekt ist in der Funktion selbst natürlich nicht irgendein Objekt, was ich aber sagen wollte, dass die Eigenschaften von keinem einzigen Objekt da einfach in den Scope gepackt werden. Auch nicht die des Funktionsobjektes. Sonst müsstest du ja in jeder Funktion im Scope ein "call" und "apply" und "toString" und und und ... haben.
Merk' dir einfach, dass nur der globale Scope besonders ist und Variablen da drin auch im gloabl bzw. window als Eigenschaften registriert werden - und vice versa. Ein normaler Funktionsscope hat so etwas nicht.
 
Zurück
Oben