2009-07-15 10 views
20

ich das folgende Stück Skript bin mit ein anderes zu laden:Ist der Aufruf von jQuery's getScript() unzuverlässig oder mache ich etwas falsch?

$.getScript("CAGScript.js", function() { 
    try { 
     CAGinit(); 
    } catch(err) { 
     console.log(err); 
    } 
}); 

Die Idee ist, dass $ .getScript das Skript lädt, führt dann den Rückruf, wenn es fertig ist. CAGInit() ist eine Funktion, die in CAGScript.js lebt.

Das Problem ist, dass etwa die Hälfte der Zeit, CAGInit() (in keinem Browser) feuert. Das Protokollieren an der Firebug-Konsole meldet, dass es nicht definiert ist. Der Rest der Zeit funktioniert es perfekt.

Hat jemand irgendwelche Ideen, was ich falsch mache?

Danke.

+2

Beachten Sie, dass in der Dokumentation angegeben ist, dass der Rückruf ausgeführt wird, sobald das Skript geladen wurde, und nicht unbedingt, sobald das Skript ausgeführt wurde. – Flimm

Antwort

10

Wenn die Datei auf der gleichen Domäne gehalten wird, dann wird jQuery XHR verwenden, um den Inhalt abrufen und wird global „eval“ dann es. Dies sollte gut funktionieren, aber wenn Sie Probleme haben, dann würde ich vorschlagen, die alternative Methode der Injektion eines Skript-Tags. Leider hat jQuery diese Funktionalität nicht aussetzen, so dass Sie es selbst tun werden müssen:

var script = jQuery('<script/>').attr('src', 'CAGSCript.js').appendTo('head'); 

var timer = setInterval(function(){ 
    if (window.CAGInit !== undefined) { 
     clearInterval(timer); 
     script.remove(); 
     // Do your stuff: 
     CAGInit(); 
    } 
}, 200); 

Es abstrahieren wäre am besten, diese zu einer Funktion; Das obige ist nur ein Beispiel ...

+0

Dieser scheint den Trick gemacht zu haben, danke :) –

+3

Beachten Sie, dass dieser Code auf Abruf basiert. Das Intervall scheint vernünftig, und es wird in vielen Fällen gut funktionieren, aber es ist sicherlich keine ideale oder generische Lösung. Polling auf diese Weise bedeutet, dass es fast immer eine erhebliche Verzögerung zwischen dem Zeitpunkt, wenn der Code bereit ist und wenn der Benutzer davon profitiert. – natevw

+0

@ 999, warum müssen Sie nicht auch das Attribut 'type' hinzufügen? –

0

Ich denke, Sie können starten, indem Sie testStatus der Callback-Funktion überprüfen, um sicherzustellen, dass das Skript wirklich geladen wurde. Callback-Funktion zwei Parameter hat, mehr defails auf diejenigen, finden Sie auf jQuery Docs

$.getScript("CAGScript.js", function (data, textStatus) { 
    if (textStatus === "success") { 
     try { 
      CAGinit(); 
     } catch(err) { 
      console.log(err); 
     } 
    } else { 
     console.log("script not loaded"); 
    } 
}); 
+1

Ich dachte, das hätte es behoben, aber ich sehe immer noch gelegentlich "ReferenceError: CAGinit ist nicht definiert", auch wenn textstatus === "success". Ich werde die Nicht-XHR-Lösung von J-P ausprobieren. –

9

hatte gerade das gleiche Problem auf Firefox, löste es mit einem kleinen Hack.

Anwendung auf Ihrem Beispiel:

$.getScript("CAGScript.js", function (xhr) { 
    try { 
     CAGinit(); 
    } catch(err) { 
     eval(xhr); 
     CAGinit(); 
    } 
}); 

Grundsätzlich eine Bewertung der XHR Reaktion zwingen, wenn sie von selbst dies nicht tut.

+0

Fantastisch, danke. Ich versuche es das nächste Mal, wenn ich ein Skript laden muss :) –

+0

Ausgezeichnete Idee; löste dieses Problem für mich :) – thismax

+0

Es ist wahrscheinlich, dass dies das Skript zweimal bewerten wird. Ich würde sicherstellen, dass es idempotent ist (d. H. Mehr als ein Lauf = kein Problem). Oder gehen Sie stattdessen mit einem Intervall. – Kevin

1

Ja, ich habe auch entdeckt, dass GetScript in FireFox unzuverlässig ist und den Callback auslöst, bevor das Skript heruntergeladen und/oder ausgeführt wurde. (Verwenden von JQuery 1.41 & FireFox 3.6. Problem scheint IE, Chrome oder Opera nicht zu beeinträchtigen.)

Ich habe nicht umfangreiche Tests durchgeführt, aber es scheint nur mit einigen bestimmten Skripts passieren ... nicht sicher warum .

RaYells Vorschlag funktioniert nicht, da getScript Erfolg meldet, obwohl das Skript noch nicht ausgewertet wurde. Pieter's Vorschlag bewirkt in den meisten Fällen, dass der Code zweimal ausgewertet wird, was ineffizient ist und Fehler verursachen kann.

Diese Alternative scheint zu funktionieren, wo GetScript nicht funktioniert. Beachten Sie, dass anscheinend ein SCRIPT-DOM-Element hinzugefügt wird, während getScript XHR verwendet.

http://www.diveintojavascript.com/projects/sidjs-load-javascript-and-stylesheets-on-demand

+0

Genau so funktioniert JPs obige Antwort :) –

22

bemerkte ich das gleiche Problem mit FF 3.6.

Eine Lösung besteht darin, das Skript synchron zu laden.

Wie in jQuery's documentation erwähnt, ist getScript Abkürzung für:

$.ajax({ 
    url: url, 
    dataType: 'script', 
    success: success 
}); 

Alles funktioniert gut, wenn ich folgendes statt getScript verwenden:

$.ajax({ 
    url: url, 
    dataType: 'script', 
    success: success, 
    async: false 
}); 
+1

Beste Lösung für mich - das Laden mehrerer Skripte, die alle auf das Skript angewiesen sind, das vor –

+0

geladen wurde Wow, kann nicht glauben, dass ich nicht darüber nachgedacht habe, bis ich dein gelesen habe Antworten. Wir sind so an Async-alles gewöhnt! – Kevin

+0

Blockiert das, bis das Skript geladen wird oder bis das Skript geladen und ausgeführt wird? – Flimm

3

ich etwas von diesem Problem nicht auf Chrome bekommen haben auch. jQuery ruft gelegentlich den Erfolgsrückruf auf, als ob alles in Ordnung wäre, aber das Skript wurde nicht richtig geladen. In unserem Fall war die Lösung einfach das Vertrauen auf jQuery zu ändern:

<script> 
    $.getScript("helpers.js", function() { 
     // use helpers....or: EXPLODE (wheeeee!) 
     helpers.doSomething(); 
    }); 
</script> 

Um Vertrauen in den Browser:

<script src="helpers.js"></script> 
<script> 
    helpers.doSomething(); 
</script> 

Ich bin wieder zu finden und wieder, dass „weniger jQuery == weniger Rand Fälle = = weniger Fehler ". Und normalerweise auch besser lesbaren Code!

20

Ich wollte nur einige Einblicke bieten, die ich zu diesem Thema habe. Der Rückruf wird nicht ausgelöst, wenn ein Fehler in dem Code auftritt, den Sie laden, und (zumindest in Chrome mit jQuery 1.7.1) wird der Fehler verschluckt. Ich entdeckte, dass ich eine lockige geschweifte Klammer von der automatischen Vervollständigung in dem Code hatte, den ich geladen habe, und die Rückruffunktion nicht ausgelöst wurde. Intermittierendes Verhalten hier könnte durch Ändern des geladenen Codes zwischen den Tests verursacht werden.

+0

Danke, das war genau das Problem. Man kann [JLint online] (http://www.javascriptlint.com/online_lint.php) verwenden, um die JS-Datei zu validieren. –

0

Ich wollte etwas ähnlich zu Auto_load in PHP in JS implementiert haben, die typische Lösung ist Try-Catch für alle Funktionen .. wenn die Funktion fehlt, springen wir zum Download seiner Bibliothek .. Meine Lösung stammt aus Pieter Lösung wie folgt:

function CheckUserPW(username,password){ 
    try{ 
     loginCheckUserPW(username,password); 
    } catch(err) { 
     $.getScript('login.js', function(xhr){ 
      eval(xhr); 
      loginCheckUserPW(username,password); 
     }); 
    } 
} 
3

um sicher CAGScript.js zu machen, ist geladen und ausgeführt, bevor CAGinit Funktion aufrufen, der sicherste Weg ist es, die Funktionsaufruf innerhalb CAGScript.js zu haben.

CAGScript.js:



    ... 
    /* 
    your code 
    */ 
    function CAGinit(){ 
    ... 
    } 
    ... 
    /* last line */ 
    CAGinit(); 

und dann, nur in der Hauptdatei getScript() aufrufen:



    $.getScript("CAGScript.js"); 

+0

Liebe es. Warum denken wir nie an die einfachen Lösungen zu der Zeit? –

0

Scheint, wie jQuery Cross-Domain und gleiche Domain-Anfragen nur jetzt gut behandelt. Bei domainübergreifenden Anfragen wird ein Skript-Tag hinzugefügt und Fehler- und Ladeereignisse abonniert und die Aufrufe von done und error korrekt aufgerufen. Dies ist nur dann ein Fehler, wenn eine Anfrage fehlschlägt. Fehler beim Auswerten des Skripts werden weiterhin als Erfolg gewertet Anfrage ist betroffen. Für den gleichen Ursprung, wird es eine XHR-Anfrage machen und dann ein globalesEval machen und sobald es fertig ist, rufen Sie Ihren done Callback auf, wenn irgendetwas in diesem Prozess fehlschlägt, ruft es Ihren Fehler Callback auf.

Die Verwendung von XHR hat ein paar Probleme, es bricht den Debugger, Quellkarten und es beruht auf einem globalEval, das Probleme mit ContentSecurityPolicy hat. Zu diesem Zweck fügen wir beim Laden von Skripten einfach ein Skript-Tag hinzu.

var scriptElement = $("<script>").prop({src: url, async: true}); scriptElement.one('load',()=> ...); scriptElement.one('error', (evt)=> ...); document.head.appendChild(scriptElement[0]);

Wenn Sie es ohne jQuery Suche in this article zum dynamischen Import-Skripte tun wollen

Hoffnung, das hilft.

0

Mein Weg ist

setTimeout(function(){ 
    $.getScript("CAGScript.js"); 
    }, 
2000); 

das gleiche Problem, das wir auch in Winkel konfrontiert werden, wenn wir aktualisieren Daten in Rahmen $ wollen, und es wird unter Verwendung von $ timeout in gleicher Weise in Winkel gelöst ...

Verwandte Themen