2009-07-15 9 views
20

Sto utilizzando il seguente pezzo di script per caricare un altro:La richiamata su getScript di jQuery è inaffidabile o sto facendo qualcosa di sbagliato?

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

L'idea è che $ .getScript carica il copione, poi esegue la richiamata quando è fatto. CAGInit() è una funzione che vive in CAGScript.js.

Il problema è che circa la metà del tempo, CAGInit() non viene attivato (in qualsiasi browser). La registrazione alla console di Firebug segnala che non è definito. Il resto del tempo funziona perfettamente.

Qualcuno ha qualche idea su cosa sto facendo male?

Grazie.

+2

Si noti che la documentazione dice che il callback viene eseguito una volta che lo script è stato caricato, e non necessariamente una volta che lo script è stato eseguito. – Flimm

risposta

10

Se il file si svolge sullo stesso dominio allora jQuery utilizzerà XHR per recuperare il contenuto e poi sarà globalmente "eval" esso. Questo dovrebbe funzionare bene, ma se hai problemi allora ti suggerirei di usare il metodo alternativo per iniettare un tag script. Purtroppo, jQuery non esporre questa funzionalità in modo da dovrete farlo da soli:

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); 

Sarebbe meglio per astrarre questo per una funzione; quanto sopra è solo un esempio ...

+0

Questo sembra aver fatto il trucco, grazie :) –

+3

Si noti che questo codice si basa sul polling. L'intervallo sembra ragionevole e funzionerà bene in molti casi, ma non è certamente una soluzione ideale o generica. Sondare in questo modo significa che ci sarà quasi sempre un ritardo significativo tra quando il codice è pronto e quando l'utente ne trae il beneficio. – natevw

+0

@ 999, perché non è necessario aggiungere anche l'attributo 'tipo'? –

0

Penso che si possa iniziare controllando testStatus della funzione di callback per assicurarsi che lo script sia stato realmente caricato. funzione di callback ha due parametri, più defails su quelli che si possono trovare sul 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

Ho pensato che fosse stato corretto, ma di tanto in tanto vedo ancora "ReferenceError: CAGinit non definito" anche quando textstatus === "success". Darò a disposizione la soluzione non XHR di J-P. –

9

Appena avuto lo stesso problema su firefox, risolto con un piccolo trucco.

applicandolo alle esempio:

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

Fondamentalmente forzando una valutazione della risposta XHR se non riesce a farlo da solo.

+0

Fantastico, grazie. Ci provo la prossima volta che ho bisogno di caricare uno script :) –

+0

Ottima idea; risolto questo problema per me :) – thismax

+0

È probabile che valuterà lo script due volte. Mi assicurerei che fosse idempotente (cioè più di una corsa = nessun problema). Oppure vai con un intervallo invece. – Kevin

1

Sì, ho scoperto anche che getScript non è affidabile in FireFox, attiva la richiamata prima che lo script sia stato scaricato e/o eseguito. (Usando JQuery 1.41 & FireFox 3.6. Problema non sembra affliggere IE, Chrome o Opera.)

Non ho eseguito test approfonditi, ma sembra che accada solo con alcuni script specifici ... non so perché .

Il suggerimento di RaYell non funziona, poiché getScript segnalerà il successo anche se lo script non è stato ancora valutato. Il suggerimento di Pieter nella maggior parte dei casi fa sì che il codice venga valutato due volte, il che è inefficiente e può causare errori.

Questa alternativa sembra funzionare dove non lo è getScript. Si noti che sembra aggiungere un elemento DOM SCRIPT, mentre getScript XHR.

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

+0

Sì, è più o meno come funziona la risposta di JP sopra :) –

22

ho notato lo stesso problema con 3.6 FF.

Una soluzione è caricare lo script in modo sincrono.

Come accennato in jQuery's documentation, getScript è una scorciatoia per:

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

Tutto funziona bene se uso il seguente invece di getScript:

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

La migliore soluzione per me - caricare più script che si basano tutti sullo script caricato prima di –

+0

Wow, non posso credere di non aver pensato a questo finché non ho letto il tuo risposta. Siamo così abituati ad asincronizzare tutto! – Kevin

+0

Questo blocco verrà caricato fino a quando non verrà caricato lo script o finché lo script non verrà caricato ed eseguito? – Flimm

3

Ho ottenuto po 'da questo problema su Chrome anche. jQuery chiama occasionalmente il callback di successo come se tutto andasse bene, ma lo script non è stato caricato correttamente. Nel nostro caso, la soluzione era quella di cambiare semplicemente da fidarsi jQuery:

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

Per confidando browser:

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

mi sto trovando ancora e ancora che "meno jQuery == meno casi limite = = meno bug ". E di solito anche codice più leggibile!

20

Volevo solo offrire alcune informazioni che ho su questo problema. Il callback non scatterà se c'è un errore nel codice che stai caricando e (almeno su Chrome con jQuery 1.7.1) l'errore verrà inghiottito. Ho scoperto che avevo una parentesi graffa vagante da completamento automatico nel codice che stavo caricando e la funzione di callback non ha sparato. Il comportamento intermittente qui potrebbe essere causato cambiando il codice caricato tra i test.

+0

Grazie, è stato proprio questo il problema. Si può usare [JLint online] (http://www.javascriptlint.com/online_lint.php) per convalidare il file JS. –

0

Volevo avere qualcosa di simile a auto_load in PHP implementato in JS, la soluzione tipica è l'uso di try-catch su tutte le funzioni .. quando manca la funzione saltiamo a scaricare la sua libreria .. La mia soluzione è presa da soluzione Pieter come segue:

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

al fine di assicurarsi che CAGScript.js viene caricato ed eseguito prima di chiamare la funzione CAGinit, il modo più sicuro è quello di avere la chiamata di funzione all'interno CAGScript.js.

CAGScript.js:



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

e poi, nel file principale basta chiamare getScript():



    $.getScript("CAGScript.js"); 

+0

Love it. Perché non pensiamo mai alle soluzioni semplici in quel momento? –

0

Sembra come jQuery gestisce tra domini e le richieste di domini stessi solo bene ora. Per le richieste cross domain, aggiungerà un tag script e sottoscriverà l'errore e caricherà gli eventi e chiamerà appropriatamente i callback fatti ed errori, è un errore solo se una richiesta fallisce, gli errori che valutano lo script saranno comunque considerati un successo fino al richiesta è interessato. Per la stessa origine, eseguirà una richiesta XHR e quindi eseguirà un valore GlobalEval e, una volta terminato, richiamerà la richiamata eseguita, in caso contrario, chiamerà il callback di errore.

L'utilizzo di XHR ha alcuni problemi, interrompe il debugger, le sourcemaps e si basa su un valore globale, che presenta problemi con ContentSecurityPolicy. Per questo una coerenza, aggiungiamo semplicemente un tag script quando cariciamo gli script.

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

Se si vuole fare senza jQuery di ricerca per gli script in modo dinamico l'importazione in this article

Spero che questo aiuti.

0

Il mio modo è

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

lo stesso problema che abbiamo di fronte in angolare anche quando si vuole aggiornare i dati in $ portata e si è risolto utilizzando $ timeout nel stesso modo in angolare ...

Problemi correlati