Frage zum Wiki-Artikel ‚Organisation von JavaScripten‘
Marc T
- frage zum wiki
Hallo, war es nichtmal "guter" Programmierstil, die Anweisung <script src="externe Javascript-datei"></script> in den <head> zu schreiben? Aber da war doch was, dass dann mit javascript nochnicht auf referenzierte HTML-Elemente zugegriffen werden kann, da die ja noch garnicht geladen sind?! Wie wird das heute gehandhabt?
Marc
Hallo Marc T,
war es nichtmal "guter" Programmierstil, die Anweisung <script src="externe Javascript-datei"></script> in den <head> zu schreiben?
Aber da war doch was, dass dann mit javascript nochnicht auf referenzierte HTML-Elemente zugegriffen werden kann, da die ja noch garnicht geladen sind?! Wie wird das heute gehandhabt?
Grundsätzlich gibt es da mindestens zwei Möglichkeiten:
Bis demnächst
Matthias
Hallo
War es nichtmal "guter" Programmierstil, die Anweisung <script src="externe Javascript-datei"></script> in den <head> zu schreiben? Aber da war doch was, dass dann mit javascript noch nicht auf referenzierte HTML-Elemente zugegriffen werden kann, da die ja noch garnicht geladen sind?! Wie wird das heute gehandhabt?
Das hast du richtig erkannt: Wenn du dein Script ohne weitere Angaben im Head einbindest, dann wird beim Parsen des Dokuments an dieser Stelle angehalten und erst das Script geladen und ausgeführt, bevor es weitergeht. Wenn dann innerhalb des Scripts versucht wird, auf Elemente zuzugreifen, die im Quelltext nach dem Script, also etwa im Body notiert sind, dann wird dieser Zugriff fehlschlagen, da die Elemente zu diesem Zeitpunkt noch nicht in entsprechende DOM-Objekte übersetzt wurden.
Um mit diesem Problem umzugehen, gibt es mehrere Optionen, wobei die einfachste ist, das Script am Ende des Body einzubinden. Auf diese Weise ist sichergestellt, dass alle Elemente zum Zeitpunkt der Ausführung des Scripts bereits in ihre DOM-Repräsentation übersetzt wurden.
Alternativ dazu kann die Scriptausführung aber auch von einem Ereignis abhängig gemacht werden, wobei die Wahl davon abhängt, ob es genügt, dass alle Elemente verfügbar sind, oder ob es erforderlich ist, auf weitere externe Ressourcen wie Bilder oder Stylesheets zu warten.
<head>
<script>
window.addEventListener('DOMContentLoaded', function ( ) {
console.log('DOM is ready');
});
</script>
</head>
Das Ereignis DOMContentLoaded feuert, sobald das Dokument fertig geparst ist, also alle im Dokument notierten Elemente in DOM-Objekte übersetzt wurden. Wenn also nicht auf externe Ressourcen gewartet werden muss, dann wäre die Überwachung dieses Ereignisses das Mittel der Wahl.
<head>
<script>
window.addEventListener('load', function ( ) {
console.log('all ressources loaded');
});
</script>
</head>
Ist dein Programm hingegen darauf angewiesen, dass vor dessen Ausführung alle eingebundenen Ressourcen fertig geladen worden sind, dann sollte besser auf das Ereignis load reagiert werden, das solange auf sich warten lässt, bis tatsächlich alle Bilder, Stylesheets und sonstigen Ressourcen geladen wurden.
<head>
<script>
window.addEventListener('DOMContentLoaded', function ( ) {
const picture = document.images['picture'];
picture.addEventListener('load', function ( ) {
console.log('picture loaded');
});
console.log('DOM is ready');
});
</script>
</head>
<body>
<img id="picture" src="source.jpg" alt="text">
</body>
Hierbei ist allerdings noch anzumerken, dass das Ereignis load nicht nur global auf dem Objekt window überwacht werden kann. Das heißt, wenn zum Beispiel ein Teil des Programms erst dann ausgeführt werden soll, wenn eingebundene Bilder fertig geladen wurden, dann wäre es auch möglich, zwar den allgemeinen Einstiegspunkt für das Programm an das Ereignis DOMContentLoaded zu knüpfen, dann aber innerhalb des dazugehörigen Eventhandlers für die nun zur Verfügung stehenden Objekte, welche die Img-Elemente repräsentieren, weitere Eventhandler für das Ereignis load zu registrieren.
Auf diese Weise können diejenigen Funktionen, die nicht darauf warten müssen, bis alle Bilder fertig geladen wurden, schon vorher ausgeführt werden.
<head>
<script src="source.js" defer></script>
</head>
Eine weitere Möglichkeit das Problem der Unvollständigkeit der DOM-Konstruktion zum Zeitpunkt der Scriptausführung anzugehen besteht schließlich darin, für das Script-Element das Attribut defer zu notieren. Dieses sorgt dafür, dass ein Script zwar parallel zum Parsen des Dokuments geladen wird, die Ausführung jedoch erst erfolgt wenn dieser Prozess abgeschlossen ist. Dies funktioniert allerdings nur mit solchen Scripten, die aus einer externen Datei geladen werden und nicht mit solchen, deren Code direkt im Dokument notiert ist.
Du siehst also, dass es nicht die eine perfekte Lösung für das Problem gibt, sondern mehrere mögliche Lösungen, und welche die beste ist, hängt von den Voraussetzungen im Einzelfall ab.
Viele Grüße,
Orlok
@@Orlok
Das hast du richtig erkannt: Wenn du dein Script ohne weitere Angaben im Head einbindest, dann wird beim Parsen des Dokuments an dieser Stelle angehalten und erst das Script geladen und ausgeführt, bevor es weitergeht. Wenn dann innerhalb des Scripts versucht wird, auf Elemente zuzugreifen, die im Quelltext nach dem Script, also etwa im Body notiert sind, dann wird dieser Zugriff fehlschlagen, da die Elemente zu diesem Zeitpunkt noch nicht in entsprechende DOM-Objekte übersetzt wurden.
Wobei das mit dem Fehlschlagen nur ein Teil des Problems ist.
Der andere Teil ist „wird beim Parsen des Dokuments an dieser Stelle angehalten“ – was eine Verzögerung der Darstellung der Seite bedeutet, die vom Nutzer je nach Bandbreite deutlich wahrgenommen wird. Oder auch nicht, weil er die Seite schon wieder verlässt, ohne das Laden abzuwarten.
Deshalb JavaScript möglichst so einbinden, dass es das Rendern der Seite nicht blockiert.
LLAP 🖖
sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|