6 Stimmen

Dynamische Einbindung von Javascript-Dateien nur einmal

Ich habe eine Javascript-Funktion, die ich schreibe, die verwendet wird, um eine externe JS-Datei enthalten, aber nur einmal. Der Grund, warum ich eine solche Funktion benötige, ist, dass sie aufgerufen wird, wenn ein Inhalt über AJAX geladen wird und ich seitenbezogenen Code für diesen Inhalt ausführen muss (nein, nur mit .live nicht abdecken wird).

Hier ist mein Versuch, der Kürze halber gekürzt:

$.include_once = function(filename) {
    if ($("script[src='" + filename + "']").length === 0) {
        var $node = $("<script></script>")
            .attr({
                src : filename,
                type : "text/javascript"
            })
        ;
        $(document.body).append($node);
    }
};

Das funktioniert einwandfrei: Die Funktion wird aufgerufen, die externe Datei wird geladen, und diese Datei wird beim Laden ausgeführt. Perfekt.

Das Problem ist, dass die externe Datei immer wieder neu geladen wird: Die Abfrage, mit der ich das Vorhandensein des Skripts prüfe, findet immer nichts!

Bei der Fehlersuche habe ich einige Zeilen hinzugefügt:

alert($("script").length);     // alerts: 4
$(document.body).append($node);
alert($("script").length);     // alerts: 4

Wenn ich mir den dynamischen Quelltext ansehe (die HTML-Registerkarte von Firebug), kann ich das Skript-Tag überhaupt nicht finden.

Ich weiß, dass ich ein Array von Dateien beibehalten könnte, die ich zuvor eingeschlossen habe, aber ich hoffte, mit einer Methode wie diese zu gehen, die (wenn es funktioniert), scheint ein bisschen robuster, da nicht alle JS-Dateien auf diese Weise eingeschlossen werden.

Kann jemand das Verhalten in diesem zweiten Schnipsel erklären?

5voto

Crescent Fresh Punkte 111444

JQuery ist in diesem Fall ein bisschen dumm-dumm; es tut überhaupt nicht das, was man erwarten würde. Wenn Sie append($node) jQuery tut dies:

jQuery.ajax({
  url: $node.src,
  async: false,
  dataType: "script"
})

Huch! Für lokale Dateien (z.B. in der gleichen Domäne) führt jQuery eine Standard XMLHttpRequest für den .js-Dateikörper, und fährt damit fort, ihn durch einen ganzen verworrenen Prozess der Erstellung einer <script> Tag (wieder!) und die Einstellungen sind Inhalt in den Körper Ihrer .js-Datei einfügen. Dies soll simulieren eval sondern im globalen Kontext.

Für domänenübergreifende Dateien, da es nicht die Standard XMLHttpRequest aufgrund der "same-domain"-Richtlinie erstellt jQuery erneut eine <script> Element und fügt es in <head> .

Sowohl in den lokalen als auch in den domänenübergreifenden Fällen oben jQuery schließlich dazu kommt, dies zu tun:

head.removeChild(script);

Und Ausleger Ihr .length überprüfen! Schade.

Nun zu Ihrem Problem: Belästigen Sie jQuery nicht mit diesem Problem. Tun Sie einfach

document.getElementsByTagName('head')[0]
  .appendChild(
    document.createElement('script')
  )
  .src = filename;

Damit wird das erreicht, was Sie erwarten, vor allem, wenn Sie es später abfragen.

0 Stimmen

Ausgezeichnete Antwort. Ich dachte, jQuery war ein bisschen zu clever für sich selbst oder etwas.

0 Stimmen

@nickf: Ich fühle mich so über die meisten jQuery's Innereien (zu schlau, dass ist ;) Es gibt viele notwendige Übel in dort ich denke.

3voto

Jordan Running Punkte 96893

Sie versuchen, ein Problem zu lösen, das bereits mehrfach gelöst wurde. Versuchen Sie LazyLoad zum Beispiel. Ähnliche Plugins gibt es auch für jQuery.

0voto

Frunsi Punkte 7019

Anstatt das Attribut "source" des Skript-Tags zu setzen, setzen Sie das Attribut "text" des Skript-Tags. Dies funktioniert in allen modern Browsern (die Anwendung, in der ich das in der Praxis verwende, unterstützt IE6 nicht, also weiß ich nichts von diesem Fiesling...).

In der Praxis würde es so aussehen (Sie MÜSSEN Code hinzufügen, um doppelte Einbindung auf sich selbst zu vermeiden - z.B. ein einfaches Array aller bereits geladenen Skripte, obwohl das sehr anwendungsspezifisch ist, und warum sollten Sie überhaupt Code zweimal laden? versuchen Sie, doppelt geladenen Code zu vermeiden...!):

var script_source_code_string = <some dynamically loaded script source code>;
var $n = $("<script></script>");
$n.get(0).text = script_source_code_string;
$(document.body).append($n);

Oder noch einfacher (ohne jquery, mein Code kennt jquery in diesem Stadium nicht, es kann auch dynamisch geladen werden):

var script_source_code_string = <some dynamically loaded script source code>;
var s = document.createElement('script');
document.getElementsByTagName('head')[0].appendChild(s);
s.text = script_source_code_string;

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X