Wann wird eine externe JavaScript-Datei nachgeladen?
Chris
- javascript
Hallo!
Ich kenne mich (noch) nicht sonderlich mit JavaScript aus. In einem Buch bin ich nun auf einen Quellcode gestoßen, der so ähnlich ausschaut:
JavaScript-Datei datei.js:
ausgabe = 'Hallo!';
HTML-Datei:
...
<script type="text/javascript" src="datei.js"></script>
</head>
<body>
<script type="text/javascript">
<!--
document.write(ausgabe);
//-->
...
Angeblich ist nun nicht definiert, wann die externe JavaScript-Datei nachgeladen wird. D.h. dass die Variable ausgabe zum Zeitpunkt der Ausgabe der document.write-Funktion möglicherweise noch nicht definiert sein könnte. Das Resultat wäre dann 1. eine JavaScript-Fehlermeldung, 2. dass nichts ausgegeben wird.
Um ehrlich zu sein, habe ich über dieses mögliche Problem bisher noch nirgends etwas gelesen. Ich hatte stets angenommen, dass die JavaScript-Datei in einem solchen Fall quasi erst einmal komplett in das HTML-Dokument eingebunden wird, bevor es nach dem </script> weitergeht.
In der 4. Auflage von David Flanagans >JavaScript - Das umfassende Referenzwerk< habe ich auf S. 219 folgenden Abschnitt gefunden:
Wie oben gesagt, werden über das src-Attribut eingebundene Scripten in der gleichen Reihenfolge ausgeführt wie Scripten, die direkt in der HTML-Datei stehen. Das bedeutet, dass sowohl der HTML-Parser als auch der JavaScript-Interpreter anhalten und warten müssen, bis die externe JavaScript-Datei geladen wurde.<
Demnach ist die Aussage in dem anderen Buch doch falsch? Das hat mich doch etwas verunsichert.
Hi,
Angeblich ist nun nicht definiert, wann die externe JavaScript-Datei nachgeladen wird.
es mag sein, dass es nicht definiert ist - ehrlich gesagt habe ich nie versucht, dies herauszufinden. Ich kann Dir aber sagen, wie es in der Realität ist:
Wie oben gesagt, werden über das src-Attribut eingebundene Scripten in der gleichen Reihenfolge ausgeführt wie Scripten, die direkt in der HTML-Datei stehen. Das bedeutet, dass sowohl der HTML-Parser als auch der JavaScript-Interpreter anhalten und warten müssen, bis die externe JavaScript-Datei geladen wurde.<
Nämlich exakt so. Es wäre ja auch traurig, wenn man den Worten eines David Flanagan nicht trauen könnte ;-)
Demnach ist die Aussage in dem anderen Buch doch falsch?
Wenn zwei technische Fachbücher widersprüchliche Aussagen treffen, würde ich derjenigen im O'Reilly-Buch eher Glauben schenken. Von was für einem anderen Buch reden wir hier eigentlich?
In der 4. Auflage von David Flanagans >JavaScript - Das umfassende Referenzwerk< habe ich auf S. 219 folgenden Abschnitt gefunden:
Ich habe "nur" die 5. Auflage hier, die auf Seite 219 ein Code-Beispiel enthält. Kannst Du den Abschnitt mit seitenneutraleren Angaben spezifizieren?
Cheatah
Wenn zwei technische Fachbücher widersprüchliche Aussagen treffen, würde ich derjenigen im O'Reilly-Buch eher Glauben schenken. Von was für einem anderen Buch reden wir hier eigentlich?
Das erste Buch würde ich zumindest nicht als Java Script-Fachbuch bezeichnen. Der Buchtitel lautet >No Spam!<. Der Titel ist im entwickler press-Verlag erschienen. Der Inhalt dreht sich um die Vermeidung von Spam, indem man schon auf der Internetseite E-Mail-Adressen tarnt, damit sie nicht von Spidern gefunden werden.
Ein möglicher Weg hierzu wäre u.a. die Ausgabe der Adressen per Java Script. Dabei wird davon ausgegangen, dass die Spider (noch) kein Java Script beherrschen und die Adressen daher auch noch nicht interpretieren können. (2005) Natürlich steht die Adresse immer noch im Klartext in der externen Java Script-Datei, was auch thematisiert wird. Aber die meisten Spider würden schon keine externen Java Script-Dateien einlesen, da sie nichts damit anfangen könnten.
Ich finde es zwar auch nicht unbedingt so geschickt, dass per JavaScript zu machen, - was der Autor auch nicht behauptet, sondern nur alle denkbaren Techniken vorstellt - aber zumindest wollte ich alles mal gelesen und verstanden haben. Und da habe ich diesen Quellcode gefunden, den ich nur zur Darstellung ein klein wenig abgeändert habe. Da mir das Problem nicht bewusst war, dachte ich mir, ich frage lieber noch mal nach, bevor es nur bei mir lokal einwandfrei läuft. ;-)
Ich habe "nur" die 5. Auflage hier, die auf Seite 219 ein Code-Beispiel enthält. Kannst Du den Abschnitt mit seitenneutraleren Angaben spezifizieren?
In meiner Auflage ist es der letzte Absatz unter:
12.3 Ausführung von JavaScript-Programmen
12.3.1 Skripten
Danke!
Hallo,
Angeblich ist nun nicht definiert, wann die externe JavaScript-Datei nachgeladen wird.
Das stimmt, in HTML ist das nicht näher definiert (in Netscape JavaScript glaube ich auch nicht explizit). Allerdings gibt es da ein ungeschriebenes Gesetz, an das sich alle halten und das HTML 5 kodifizieren wird:
http://www.whatwg.org/specs/web-apps/current-work/#scripting0
D.h. dass die Variable ausgabe zum Zeitpunkt der Ausgabe der document.write-Funktion möglicherweise noch nicht definiert sein könnte. Das Resultat wäre dann 1. eine JavaScript-Fehlermeldung, 2. dass nichts ausgegeben wird.
Das ist in der Praxis nicht der Fall.
Selbst wenn, könntest du den Fall einfach abdecken, indem du prüfst, ob die entsprechenden Variablen gesetzt sind, um eine Fehlermeldung zu vermeiden.
Mathias
»»Das stimmt, in HTML ist das nicht näher definiert (in Netscape JavaScript glaube ich auch nicht explizit).
Dann hat der Autor zumindest in dieser Hinsicht Recht. Ist aber anscheinend nur ein akademisches Problem. In dem Buch klang es hingegen ziemlich gegenständlich. Das hat mich dann doch etwas "verwirrt".
»»Allerdings gibt es da ein ungeschriebenes Gesetz, an das sich alle halten und das HTML 5 kodifizieren wird:
http://www.whatwg.org/specs/web-apps/current-work/#scripting0
HTML 5 habe ich mir noch nicht angeschaut. Mal schauen, was es bringt.
Das ist in der Praxis nicht der Fall.
Selbst wenn, könntest du den Fall einfach abdecken, indem du prüfst, ob die entsprechenden Variablen gesetzt sind, um eine Fehlermeldung zu vermeiden.
Womit aber immer noch eine leere Ausgabe erfolgen könnte.
Zum Glück nur könnte, so rein theoretisch. ;-)
Jedenfalls bin ich beruhigt, dass mein "Verständnis" von Java Script nicht derart erschüttert worden ist. ;-)
Danke!
Hi,
Ich kenne mich (noch) nicht sonderlich mit JavaScript aus. In einem Buch bin ich nun auf einen Quellcode gestoßen, der so ähnlich ausschaut:
Angeblich ist nun nicht definiert, wann die externe JavaScript-Datei nachgeladen wird.
http://www.w3.org/TR/html4/interact/scripts.html#h-18.2.4
1. All SCRIPT elements are evaluated in order as the document is loaded.
2. All script constructs within a given SCRIPT element that generate SGML CDATA are evaluated. Their combined generated text is inserted in the document in place of the SCRIPT element.
3. The generated CDATA is re-evaluated.
Dazu noch http://www.w3.org/TR/html4/interact/scripts.html#adef-defer
defer [CI]
When set, this boolean attribute provides a hint to the user agent that the script is not going to generate any document content (e.g., no "document.write" in javascript) and thus, the user agent can continue parsing and rendering.
läßt eigentlich dem Browser keine Wahl.
cu,
Andreas
http://www.w3.org/TR/html4/interact/scripts.html#h-18.2.4
1. All SCRIPT elements are evaluated in order as the document is loaded.
2. All script constructs within a given SCRIPT element that generate SGML CDATA are evaluated. Their combined generated text is inserted in the document in place of the SCRIPT element.
3. The generated CDATA is re-evaluated.
Dazu noch http://www.w3.org/TR/html4/interact/scripts.html#adef-defer
defer [CI]
When set, this boolean attribute provides a hint to the user agent that the script is not going to generate any document content (e.g., no "document.write" in javascript) and thus, the user agent can continue parsing and rendering.
Da steht es ja von hochoffizieller Seite noch mal schwarz auf weiß. Ich denke, dass sich das Thema damit endgültig aufgeklärt hat. Da bin ich aber beruhigt. ;-)
Danke!
Hallo,
Da steht es ja von hochoffizieller Seite noch mal schwarz auf weiß.
Eher äußerst implizit.
Auf das Verhalten bei externen Scripts geht HTML nicht ausdrücklich ein. Der erste zitierte Abschnitt handelt davon, wie document.write zu handhaben ist. Erst beim defer-Zitat wird implizit gesagt, dass ohne defer das Parsing angehalten werden muss - aber auch nur wegen document.write. Kein Wort über externe Scripts.
Nun ging es bei deiner Frage weniger um das Verhalten bei document.write. Alleinig interessant ist deshalb die Aussage, dass Scripte auf jeden Fall in der Reihenfolge ausgeführt werden müssen, wie sie im Dokument vorkommen. Was externe Scripte betrifft, so gibt es zwar keine ausdrückliche Ausnahmeregelung, aber auch keinen ausdrücklichen Hinweis, dass erst die externe Ressource geladen und ausgeführt werden muss.
Gerade das defer-Attribut ist hoffnungslos unterspezifiziert (und der IE als einziger Browser, der es implementiert, implementiert es m.W. auch gänzlich anders, also falsch im Sinne von HTML 4). Die Zitate sagen eben nicht, was in einem solchen Fall zu tun ist:
extern.js: variable_aus_externem_script = true;
<script defer="defer" src="extern.js" type="text/javascript"></script>
<script type="text/javascript">
window.alert(variable_aus_externem_script);
</script>
Defer heißt nur, dass extern.js keine Ausgabe machen wird, also der Parser nicht mit document.write-Ausgaben rechnen muss. Das ist im Beispiel auch völlig korrekt, schließlich mach extern.js keine solchen Ausgaben - das sagt aber nichts darüber aus, ob andere, folgende Scripte im Dokument von der Ausführung von extern.js abhängen; also extern.js auf jeden Fall zuerst geladen und ausgeführt werden muss.
Was HTML 5 zu dieser Frage spezifiziert, würde ich eher als "schwarz auf weiß" bezeichnen.
Mathias
Erst beim defer-Zitat wird implizit gesagt, dass ohne defer das Parsing angehalten werden muss - aber auch nur wegen document.write. Kein Wort über externe Scripts.
Da steht aber:
When set, this boolean attribute provides a hint to the user agent that the script is not going to generate any document content (e.g., no "document.write" in javascript) and thus, the user agent can continue parsing and rendering.<
Wenn dieses Attribut gesetzt ist, (nur) dann weiß der Browser, dass er weitermachen kann.
Zwar steht das nicht explizit so da, aber wenn dieses Attribut nicht gesetzt ist - was ich doch erst mal explizit machen müsste (der Browser setzt es immerhin nicht automatisch) -, dann müsste der Browser doch erst mal mit der weiteren Ausführung des HTML-Dokuments warten; also bis das Script ausgeführt wurde - in diesem Fall also die komplette JavaScript-Datei geladen wurde. Oder interpretiere ich das dann insofern nur falsch?
Gerade das defer-Attribut ist hoffnungslos unterspezifiziert (und der IE als einziger Browser, der es implementiert, implementiert es m.W. auch gänzlich anders, also falsch im Sinne von HTML 4).
Das ist zumindest diesem Dokument aber nicht zu entnehmen. Müsste ich erst mal nach Quellen zu suchen.
Damit wären wir aber wieder am Anfang angelangt. Dann hätte der Autor des ersten Buches ja doch wieder (irgendwie) Recht.
Was macht man denn dann?
Am Ende der JavaScript-Datei eine boolean-Variable auf true setzen und diese dann im Script in der HTML-Datei abfragen, bevor man document.write ausführt?
externe JavaScript-Datei:
...
scriptx_geladen = true;
HTML-Datei:
...
<script type="text/javascript" src="..."></script>
</head>
<body>
<script type="text/javascript">
if (scriptx_geladen)
{
document.write(ausgabe);
}
...
Dann würde zumindest auf keinen Fall mehr eine Fehlermeldung ausgegeben. Aber wird dann auch garantiert noch die Variable ausgabe ausgegeben? Wenn die Bedingung bereits geprüft und als falsch ausgewertet wurde, dann wird doch nicht immer wieder geprüft, bis das externe Script endlich komplett eingelesen wurde? Dann könnte es auch sein, dass überhaupt nichts mehr ausgeben wird?
Ich könnte auch alles in eine Funktion packen:
externe JavaScript-Datei:
...
function ausgeben()
{
ausgabe = "Hallo!";
}
HTML-Datei:
...
<script type="text/javascript" src="..."></script>
</head>
<body>
<script type="text/javascript">
ausgeben();
...
Aber könnte es dann nicht vorkommen, dass dann stattdessen die Funktion noch nicht definiert ist? Dann müsste ich wieder mit einer Kontrollvariablen hantieren. Und hätte wieder die Einschränkung, dass ich nur sicherstellen könnte, dass keine Fehlermeldung ausgegeben wird, aber nicht wüsste, ob dann auch wirklich eine Ausgabe erfolgt.
Irgendwie muss man doch die korrekte Ausführung sicherstellen können. Sonst könnte man doch quasi überhaupt nichts gegen dieses Problem unternehmen. Kann doch nicht sein!?
Hallo,
Was macht man denn dann?
Am Ende der JavaScript-Datei eine boolean-Variable auf true setzen und diese dann im Script in der HTML-Datei abfragen, bevor man document.write ausführt?
Unter vielen Experten herrscht die Ansicht vor, auf document.write ganz zu verzichten. Das aktuelle Paradigma lautet DOM Scripting. Da wird die JavaScript-Logik aus dem Dokument ausgelagert, wird beim onload bzw. oncontentloaded aktiv und montiert dann ggf. Inhalte ins DOM ein.
So wird document.write oft nicht mehr benötigt, wobei es natürlich viele Ausnahmen gibt, wo man nicht darauf verzichten kann. Aber darauf zu verzichten ergibt sich eher aus einer bestimmten Weise, wie JavaScripte eingesetzt wird und funktionieren, als dass es eine Vorschrift ist.
Irgendwie muss man doch die korrekte Ausführung sicherstellen können. Sonst könnte man doch quasi überhaupt nichts gegen dieses Problem unternehmen. Kann doch nicht sein!?
Wie gesagt, in der Praxis gibt es das Problem eigentlich nicht, diese Anwendung findet man milliardenfach. Oder bist du auf Probleme damit gestoßen?
Mathias
Wie gesagt, in der Praxis gibt es das Problem eigentlich nicht, diese Anwendung findet man milliardenfach. Oder bist du auf Probleme damit gestoßen?
Nein. Aber JavaScript habe ich bisher auch eher nur zu Testzwecken lokal laufen lassen. Ich denke mal, dass dies kritischer würde, sobald die Seiten im Netz stehen würden.