Il modo migliore per utilizzare jQuery ospitato da Google, ma fallire nella mia libreria ospitata su Google


1016

Quale sarebbe un buon modo per tentare di caricare il jQuery ospitato su Google (o altre librerie ospitate da Google), ma caricare la mia copia di jQuery se il tentativo di Google fallisce?

Non sto dicendo che Google sia traballante. Ci sono casi in cui la copia di Google è bloccata (apparentemente in Iran, ad esempio).

Avrei impostato un timer e verificato l'oggetto jQuery?

Quale sarebbe il pericolo di entrambe le copie?

Non cerco davvero risposte come "usa solo Google" o "usa solo le tue". Capisco questi argomenti. Comprendo anche che è probabile che l'utente abbia la versione di Google memorizzata nella cache. Sto pensando ai fallback per il cloud in generale.


Modifica: questa parte ha aggiunto ...

Poiché Google suggerisce di utilizzare google.load per caricare le librerie Ajax e al termine esegue una richiamata, mi chiedo se questa è la chiave per serializzare questo problema.

So che sembra un po 'folle. Sto solo cercando di capire se può essere fatto in modo affidabile o meno.


Aggiornamento: jQuery ora è ospitato sul CDN di Microsoft.

http://www.asp.net/ajax/cdn/


9
Naturalmente la prima risposta è stata "non utilizzare la versione ospitata da google". :-)
Nosredna,

7
Ovviamente è stato perché se si desidera ospitare un sito Web serio, non fare affidamento su qualcun altro che ospita i propri file.
Bryan Migliorisi,

6
@Bryan Migliorisi, suppongo che Twitter non sia poi così serio? Ma ammetto che hanno avuto i loro problemi con Google come un mese fa quando Google è andato giù.
Ionuț G. Stan,

18
Il merito di usare Google o meno per l'hosting lib di JS è degno, ma è stato discusso in molti altri thread. Stavo cercando risposte tecniche riguardo al fallback di JS sui ritardi di caricamento.
Nosredna,

2
@Joe Chung: è probabile che venga memorizzato nella cache del sistema dell'utente, accelerando il caricamento della pagina. Mi fa risparmiare larghezza di banda. Utilizza la CDN di Google. Ecc.
Nosredna,

Risposte:


810

Puoi raggiungerlo in questo modo:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>

<script>
       window.jQuery || document.write('<script src="/path/to/your/jquery"><\/script>');
</script>

Questo dovrebbe essere nella tua pagina <head>e tutti i gestori di eventi pronti per jQuery dovrebbero trovarsi nel <body>per evitare errori (anche se non è a prova di errore!).

Un motivo in più per non utilizzare jQuery ospitato da Google è che in alcuni paesi il nome di dominio di Google è vietato.


35
I download di javascript non sono già bloccati (sincroni)? Mi sembra che il problema della doppia copia non sarebbe quindi un problema.
Matt Sherman,

68
I download di Javascript dovrebbero già essere sincroni, come ha affermato Matt Sherman. Altrimenti, si verificherebbero molti problemi se la pagina provasse a eseguire uno script inline che si basava su una libreria scaricata solo a metà o se un'estensione della libreria veniva eseguita senza la libreria completamente scaricata ed eseguita. Questo è anche uno dei motivi per cui Yahoo YSlow consiglia di inserire javascript alla fine delle pagine; in modo che non blocchi il download di altri elementi della pagina (inclusi stili e immagini). Per lo meno, il browser dovrebbe ritardare l'esecuzione in modo sequenziale.
gapple,

42
Piccola correzione da un fanatico del validatore: la stringa '</' non è consentita in JavaScript, perché potrebbe essere interpretata erroneamente come la fine del tag dello script (notazione del tag breve SGML). Esegui invece "<" + "/ script>". Saluti,
Boldewyn,

8
Questo esempio non funzionerà. 1) se la libreria Google Ajax non è disponibile, dovrà scadere prima di fallire. Questo potrebbe richiedere del tempo. Nel mio test di disconnessione del mio computer dalla rete ha appena provato, provato e provato e non è scaduto. 2) if (! JQuery) genererà un errore perché jQuery non è definito, quindi Javascript non sa cosa farne.
RedWolves,

32
Per verificare se jQuery è stato caricato, (! Window.jQuery) funziona bene ed è in corto, quindi il controllo del tipo.
Jörn Zaefferer,

335

Il modo più semplice e pulito per farlo di gran lunga:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="path/to/your/jquery"><\/script>')</script>

1
@jpp non per XHTML 1.0eHTML 4.01
BenjaminRH

5
Le persone continuano a chiedermi di rimuovere le type="text/javascript"parti, quindi alle persone che scrivono html per browser più vecchi, nota che ora dovrai aggiungerlo.
BenjaminRH,

6
@BenjaminRH: type="text/javascript"non era necessario anche nei browser meno recenti, poiché tutti erano impostati su Javascript. I browser molto più vecchi guardavano l' languageattributo; ma anche allora, Javascript era l'impostazione predefinita se mancava l'attributo.
Martijn,

1
@Martijn Ma mi è piaciuto il badge di convalida lucido :)
BenjaminRH il

3
@Trojan Totalmente possibile, basta impilare le chiamate. Nota che a questo punto stai aprendo nuovi host di connessioni, quindi il pipelining HTTP sarà probabilmente più veloce. ... <script src="//cdn1.com/jquery.js"></script> <script>window.jQuery || document.write('<script src="//cdn2.com/jquery.js"><\/script>')</script> <script>window.jQuery || document.write('<script src="local/jquery.js"><\/script>')</script>
Tom McKenzie il

76

Questo sembra funzionare per me:

<html>
<head>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
// has the google object loaded?
if (window.google && window.google.load) {
    google.load("jquery", "1.3.2");
} else {
    document.write('<script type="text/javascript" src="http://joecrawford.com/jquery-1.3.2.min.js"><\/script>');
}
window.onload = function() {
    $('#test').css({'border':'2px solid #f00'});
};
</script>
</head>
<body>
    <p id="test">hello jQuery</p>
</body>
</html>

Il modo in cui funziona consiste nell'utilizzare l' googleoggetto che la chiamata di http://www.google.com/jsapi carica windowsull'oggetto. Se quell'oggetto non è presente, supponiamo che l'accesso a Google non riesca. In tal caso, carichiamo una copia locale utilizzando document.write. (Sto usando il mio server in questo caso, per favore usa il tuo per testarlo).

Ho anche testato la presenza di window.google.load- Potrei anche fare un typeofcontrollo per vedere che le cose sono oggetti o funzioni come appropriato. Ma penso che questo faccia il trucco.

Ecco solo la logica di caricamento, poiché l'evidenziazione del codice sembra fallire da quando ho pubblicato l'intera pagina HTML che stavo testando:

if (window.google && window.google.load) {
    google.load("jquery", "1.3.2");
} else {
    document.write('<script type="text/javascript" src="http://joecrawford.com/jquery-1.3.2.min.js"><\/script>');
}

Anche se devo dire, non sono sicuro che se questo è un problema per i visitatori del tuo sito dovresti avere a che fare con l' API delle biblioteche di Google AJAX .

Curiosità : inizialmente ho provato a usare un blocco try..catch per questo in varie versioni ma non sono riuscito a trovare una combinazione così pulita. Sarei interessato a vedere altre implementazioni di questa idea, puramente come un esercizio.


1
Qual è il vantaggio di utilizzare google.load in questa situazione, piuttosto che caricare ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js direttamente, come suggerito da Rony? Immagino che caricarlo rilevi direttamente anche i problemi con le librerie rimosse (e se Google smettesse di servire JQuery 1.3.2). Inoltre, la versione di Rony rileva problemi di rete DOPO che www.google.com/jsapi è stato recuperato, soprattutto quando jsapi è stato caricato dalla cache? Potrebbe essere necessario utilizzare il callback di google.load per essere sicuri (o forse c'è un valore di ritorno per includere google.load nell'if (..)).
Arjan,

Se si sta verificando la presenza di Google.com, è possibile effettuare una chiamata di rete o verificare la presenza dell'oggetto "gatekeeper". Quello che sto facendo è controllare l'oggetto google e la sua funzione di "caricamento". Se entrambi falliscono, niente google e ho bisogno della versione locale. La versione di Rony in realtà ignora completamente l'URL www.google.com/jsapi, quindi non sono sicuro del motivo per cui indichi che sarà stato recuperato.
artlung,

Alla fine, tutto ciò che serve è che la libreria jquery sia caricata. Qualsiasi libreria di Google non è un requisito. Nella risposta di Rony, si sa con certezza se il caricamento da Google (o dalla cache) è riuscito. Ma nel tuo controllo per "if (window.google && window.google.load)", la libreria jquery non è ancora caricata. Il caricamento effettivo della libreria jquery non è convalidato?
Arjan,

ah, vedo come ho causato la confusione. "La versione di Rony rileva problemi di rete DOPO che www.google.com/jsapi è stata recuperata" dovrebbe leggere meglio: "La tua versione non rileva problemi di rete DOPO che www.google.com/jsapi è stata recuperata".
Arjan,

2
Di recente siamo passati all'utilizzo di Google come host jQuery; se riceviamo segnalazioni di bug da utenti bloccati, userò una variante della tua risposta per riformattare il nostro codice client. Buona risposta!
Jarrod Dixon

30

Se hai modernizr.js incorporato nel tuo sito, puoi utilizzare yepnope.js integrato per caricare gli script in modo asincrono, tra gli altri jQuery (con fallback).

Modernizr.load([{
    load : '//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'
},{
    test : window.jQuery,
    nope : 'path/to/local/jquery-1.7.2.min.js',
    both : ['myscript.js', 'another-script.js'],
    complete : function () {
        MyApp.init();
    }
}]);

Questo carica jQuery da Google-cdn. Successivamente viene controllato, se jQuery è stato caricato correttamente. In caso contrario ("no"), viene caricata la versione locale. Vengono caricati anche gli script personali: "entrambi" indica che il processo di caricamento viene avviato indipendentemente dal risultato del test.

Quando tutti i processi di caricamento sono completi, viene eseguita una funzione, nel caso 'MyApp.init'.

Personalmente preferisco questo modo di caricare script asincroni. E poiché mi affido ai test di funzionalità forniti da modernizr durante la costruzione di un sito, lo ho comunque incorporato nel sito. Quindi in realtà non ci sono spese generali.


2
Penso che ti stia perdendo il punto della domanda: come faresti a caricare lo script moernizr da un CDN?
George Filippakos,

2
Non posso raccomandare di caricare Modernizr da una CDN. Uno dovrebbe piuttosto ottenere la più piccola build personalizzata da modernizr.com.
Emanuel Kluge,

2
Quindi questa opzione ottiene +16, rispetto alla 500/200 + che stanno ottenendo le altre opzioni. Ma sembra abbastanza buono. Non è semplicemente popolare a causa dell'affidamento a Modernizer? Mi capita di usare Modernizer nel nostro sito comunque, quindi se questo è migliore delle altre risposte, qualcuno può farmelo sapere? Sono abbastanza nuovo in JQuery, quindi sono apprezzati i chiarimenti.
Redfox05,

2
Questa è stata davvero un'ottima opzione al momento della risposta, ma dal 2015 yepnope.jsè obsoleta. vedi stackoverflow.com/questions/33986561/...
Obmerk Kronen

Modernizr è stato creato per risolvere problemi proprio come questa domanda. +1
Carlos Quijano,

21

Ci sono alcune ottime soluzioni qui, ma mi piacerebbe fare un passo avanti per quanto riguarda il file locale.

In uno scenario in cui Google non riesce, dovrebbe caricare una fonte locale ma forse un file fisico sul server non è necessariamente l'opzione migliore. Ne ho parlato perché attualmente sto implementando la stessa soluzione, solo io voglio tornare a un file locale che viene generato da un'origine dati.

Le mie ragioni sono che voglio avere un po 'di idea quando si tratta di tenere traccia di ciò che carico da Google rispetto a ciò che ho sul server locale. Se voglio cambiare versione, voglio mantenere la mia copia locale sincronizzata con ciò che sto cercando di caricare da Google. In un ambiente in cui ci sono molti sviluppatori, penso che l'approccio migliore sarebbe quello di automatizzare questo processo in modo che tutto ciò che uno dovrebbe fare è cambiare un numero di versione in un file di configurazione.

Ecco la mia soluzione proposta che dovrebbe funzionare in teoria:

  • In un file di configurazione dell'applicazione, memorizzerò 3 cose: l'URL assoluto per la libreria, l'URL per l'API JavaScript e il numero di versione
  • Scrivi una classe che ottiene il contenuto del file della libreria stessa (ottiene l'URL dalla configurazione dell'app), lo memorizza nella mia origine dati con il nome e il numero di versione
  • Scrivi un gestore che estrae il mio file locale dal db e memorizza nella cache il file fino a quando non cambia il numero di versione.
  • Se cambia (nella mia configurazione dell'app), la mia classe estrarrà il contenuto del file in base al numero di versione, lo salverà come nuovo record nella mia origine dati, quindi il gestore avvierà e servirà la nuova versione.

In teoria, se il mio codice è scritto correttamente, tutto ciò che dovrei fare è cambiare il numero di versione nella mia configurazione dell'app quindi viola! Si dispone di una soluzione di fallback automatizzata e non è necessario conservare i file fisici sul server.

Cosa pensano tutti? Forse questo è eccessivo, ma potrebbe essere un metodo elegante per mantenere le tue librerie AJAX.

Ghianda


Se stai facendo tutto quel lavoro solo per jQuery, direi che è eccessivo. Tuttavia, se hai già alcuni di quei componenti in atto per altri pezzi della tua app (ad esempio se carichi già script da un DB), allora sembra piuttosto carino.
Michael Haren,

1
+1 per essere accurato e innovativo, anche se non sono convinto che il vantaggio giustifichi il tempo e la complessità degli sviluppatori.
Cory House,

20
if (typeof jQuery == 'undefined') {
// or if ( ! window.jQuery)
// or if ( ! 'jQuery' in window)
// or if ( ! window.hasOwnProperty('jQuery'))    

  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = '/libs/jquery.js';

  var scriptHook = document.getElementsByTagName('script')[0];
  scriptHook.parentNode.insertBefore(script, scriptHook);

}

Dopo aver tentato di includere la copia di Google dalla CDN.

In HTML5, non è necessario impostare il type attributo.

Puoi anche usare ...

window.jQuery || document.write('<script src="/libs/jquery.js"><\/script>');

2
+1 sembra più pulito. c'è un errore di battitura minore in cima che non posso cancellare dal momento che le sue due parentesi quadre minori dopo "non definito"
naveen,

1
La prima opzione evita l'avvertimento di Chrome[Violation] Avoid using document.write().
Bob Stein

La prima opzione, sfortunatamente, non sembra caricarsi in modo sincrono . La seconda opzione fa .
Bob Stein,

10

Potresti voler usare il tuo file locale come ultima risorsa.

Sembra che la CDN di jQuery non supporti https. In tal caso, potresti voler caricare prima da lì.

Quindi, ecco la sequenza: Google CDN => Microsoft CDN => La tua copia locale.

<!-- load jQuery from Google's CDN -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> 
<!-- fallback to Microsoft's Ajax CDN -->
<script> window.jQuery || document.write('<script src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.min.js">\x3C/script>')</script> 
<!-- fallback to local file -->
<script> window.jQuery || document.write('<script src="Assets/jquery-1.8.3.min.js">\x3C/script>')</script> 

C'è davvero bisogno di più di un fallback? se entrambi sono offline l'utente aspetterà più di un minuto prima di vedere il tuo sito
George Filippakos,

1
Non ci vuole 1 minuto per caricare uno script, non lo fa.
Edward Olamisan,

@ geo1701 ed Edward, non c'è davvero bisogno di un terzo. Anche un fallback deve ancora essere dimostrato affidabile. Se l'API di Google non funziona, non ho ancora visto alcuna garanzia che il primo tentativo fallirà affatto. Ho riscontrato uno scenario di caso in cui un CDN non è mai riuscito a caricarsi, trattenendo la pagina dal rendering, come menzionato qui: stevesouders.com/blog/2013/03/18/http-archive-jquery/…
hexalys

6

Carica in modo condizionale la versione jQuery più recente / legacy e il fallback:

<!--[if lt IE 9]>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="/public/vendor/jquery-legacy/dist/jquery.min.js">\x3C/script>')</script>
<![endif]-->
<!--[if gte IE 9]><!-->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="/public/vendor/jquery/dist/jquery.min.js">\x3C/script>')</script>
<!--<![endif]-->

Questo non è compatibile con più browser.
Josh Habdas,

Josh, sì, lo è.
Neiker,



4

Ecco una grande spiegazione su questo!

Implementa anche ritardi di caricamento e timeout!

http://happyworm.com/blog/2010/01/28/a-simple-and-robust-cdn-failover-for-jquery-14-in-one-line/


Le risposte solo link non sono utili e sono considerate di bassa qualità. Considera di copiare i bit pertinenti nella tua risposta, con l'attribuzione ovviamente alla fonte.
random_user_name

@cale_b Stai scherzando? Questa risposta ha più di 7 anni, quindi un commento del genere non è giustificato.
Stuart.Sklinar

Sì, è una vecchia risposta. Sebbene il loro suggerimento sia valido. Le risposte che sono semplicemente collegamenti altrove sono candidate alla cancellazione. Ulteriore lettore: meta.stackoverflow.com/q/8259
Rob

Sono totalmente d'accordo, modererei me stesso con i suggerimenti, ma è inutile dirlo 7 anni dopo. Avrebbe dovuto essere moderato così 7 anni fa, non 7 anni dopo.
Stuart.Sklinar

1
@ Stuart.Sklinar - se l'avessi visto 7 anni fa, l'avrei :) Mi sarei trovato qui a fare delle ricerche e a vederlo per la prima volta. Mi dispiace frustrarti - Penso che i nostri lavori su SO debbano essere amministratori del sito, il che a volte significa commentare, modificare o migliorare vecchie domande o risposte ...
random_user_name

4

Per quelle persone che usano ASP.NET MVC 5, aggiungi questo codice in BundleConfig.cs per abilitare il CDN per jquery:

bundles.UseCdn = true;
Bundle jqueryBundle = new ScriptBundle("~/bundles/jquery", "//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js").Include("~/Scripts/jquery-{version}.js");
jqueryBundle.CdnFallbackExpression = "window.jQuery";
bundles.Add(jqueryBundle);

4

AGGIORNAMENTO:
Questa risposta si è rivelata errata. Si prega di consultare i commenti per la vera spiegazione.


Alla maggior parte di voi è stata data risposta, ma per quanto riguarda la parte finale:

Quale sarebbe il pericolo di entrambe le copie?

Nessuno davvero. Sprecheresti la larghezza di banda, potresti aggiungere alcuni millisecondi scaricando una seconda copia inutile, ma non c'è nessun danno reale se arrivano entrambi. Ovviamente dovresti evitarlo usando le tecniche sopra menzionate.


5
In realtà, caricare due volte jQuery può causare molti problemi, secondo questa domanda .
ShadowCat7,

perché non lo provi tu stesso e carichi manualmente la libreria jquery due volte. quindi la risposta verrà rivelata.
luke_mclachlan,

Perché è esattamente così sbagliato? @ ShadowCat7 puoi essere più specifico sui problemi che causa? L'unico problema che vedo esplicitamente identificato nella domanda che hai collegato è "cancellare tutti i plugin caricati in precedenza". Ma questo non dovrebbe applicarsi al caricamento dello stesso file jQuery due volte back-to-back, giusto? Chiedo perché le altre soluzioni qui al fallback locale sono così contorte, e document.write è diffamato come malvagio in alcuni punti .
Bob Stein,

2

Ho creato un Gist che dovrebbe caricare dinamicamente jQuery se non è già caricato, e se l'origine non riesce, procede su fallback (ricuciti da molte risposte): https://gist.github.com/tigerhawkvok/9673154

Nota che ho intenzione di mantenere aggiornato Gist ma non questa risposta, per quello che vale!

/* See https://gist.github.com/tigerhawkvok/9673154 for the latest version */
function cascadeJQLoad(i) { // Use alternate CDNs where appropriate to load jQuery
    if (typeof(i) != "number") i = 0;
    // the actual paths to your jQuery CDNs
    var jq_paths = [
        "ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js",
        "ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.0.min.js"
    ];
    // Paths to your libraries that require jQuery
    var dependent_libraries = [
        "js/c.js"
    ];
    if (window.jQuery === undefined && i < jq_paths.length) {
        i++;
        loadJQ(jq_paths[i], i, dependent_libraries);
    }
    if (window.jQuery === undefined && i == jq_paths.length) {
        // jQuery failed to load
        // Insert your handler here
    }
}

/***
 * You shouldn't have to modify anything below here
 ***/

function loadJQ(jq_path, i, libs) { //load jQuery if it isn't already
    if (typeof(jq_path) == "undefined") return false;
    if (typeof(i) != "number") i = 1;
    var loadNextJQ = function() {
        var src = 'https:' == location.protocol ? 'https' : 'http';
        var script_url = src + '://' + jq_path;
        loadJS(script_url, function() {
            if (window.jQuery === undefined) cascadeJQLoad(i);
        });
    }
    window.onload = function() {
        if (window.jQuery === undefined) loadNextJQ();
        else {
            // Load libraries that rely on jQuery
            if (typeof(libs) == "object") {
                $.each(libs, function() {
                    loadJS(this.toString());
                });
            }
        }
    }
    if (i > 0) loadNextJQ();
}

function loadJS(src, callback) {
    var s = document.createElement('script');
    s.src = src;
    s.async = true;
    s.onreadystatechange = s.onload = function() {
        var state = s.readyState;
        try {
            if (!callback.done && (!state || /loaded|complete/.test(state))) {
                callback.done = true;
                callback();
            }
        } catch (e) {
            // do nothing, no callback function passed
        }
    };
    s.onerror = function() {
        try {
            if (!callback.done) {
                callback.done = true;
                callback();
            }
        } catch (e) {
            // do nothing, no callback function passed
        }
    }
    document.getElementsByTagName('head')[0].appendChild(s);
}

/*
 * The part that actually calls above
 */

if (window.readyState) { //older microsoft browsers
    window.onreadystatechange = function() {
        if (this.readyState == 'complete' || this.readyState == 'loaded') {
            cascadeJQLoad();
        }
    }
} else { //modern browsers
    cascadeJQLoad();
}

2

Ospitato su Google jQuery

  • Se ti interessano i browser meno recenti, principalmente le versioni di IE precedenti a IE9, questa è la versione jQuery più ampiamente compatibile
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  • Se non ti interessa oldIE, questo è più piccolo e più veloce:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

Piano di backup / fallback!

  • In entrambi i casi, dovresti utilizzare un fallback su locale nel caso in cui la CDN di Google fallisca (improbabile) o sia bloccata in una posizione da cui i tuoi utenti accedono al tuo sito (leggermente più probabile), come l'Iran o talvolta la Cina.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>if (!window.jQuery) { document.write('<script src="/path/to/your/jquery"><\/script>'); }
</script>

Riferimento: http : // we websitepeedoptimizations.com/ContentDeliveryNetworkPost.aspx


Nota che il caricamento di script tramite protocolli non sicuri apre un vettore di attacco XSS.
Josh Habdas,

2

Ritengo che dovrebbe sfuggire all'ultimo <in \ x3C nella stringa. Quando il browser vede, considera che questa è la fine del blocco di script (poiché il parser HTML non ha idea di JavaScript, non è in grado di distinguere tra qualcosa che appare in una stringa e qualcosa che in realtà è destinato a terminare lo script elemento). Quindi apparire letteralmente in JavaScript all'interno di una pagina HTML (nel migliore dei casi) causerà errori e (nel peggiore dei casi) rappresenterà un enorme buco nella sicurezza.

<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.0.0.min.js"></script>
<script>window.jQuery || document.write('<script src="js/jquery-2.0.0.min.js">\x3C/script>')</script>

2
if (typeof jQuery == 'undefined')) { ...

O

if(!window.jQuery){

Non funzionerà se la versione cdn non è caricata, poiché il browser eseguirà questa condizione e durante il download continuerà a scaricare il resto dei javascript che richiedono jQuery e restituisce errori. La soluzione era caricare gli script attraverso quella condizione.

    <script src="http://WRONGPATH.code.jquery.com/jquery-1.4.2.min.js" type="text/javascript"></script><!--  WRONGPATH for test-->
  <script type="text/javascript">
  function loadCDN_or_local(){
    if(!window.jQuery){//jQuery not loaded, take a local copy of jQuery and then my scripts
      var scripts=['local_copy_jquery.js','my_javascripts.js'];
      for(var i=0;i<scripts.length;i++){
      scri=document.getElementsByTagName('head')[0].appendChild(document.createElement('script'));
      scri.type='text/javascript';
      scri.src=scripts[i];
    }
  }
  else{// jQuery loaded can load my scripts
    var s=document.getElementsByTagName('head')[0].appendChild(document.createElement('script'));
    s.type='text/javascript';
    s.src='my_javascripts.js';
  }
  }
  window.onload=function(){loadCDN_or_local();};
  </script>

Ho riscontrato un problema nel test degli script in Google Chrome: la memorizzazione nella cache. Quindi per i test locali basta sostituire src nella sezione else con qualcosa come s.src = 'my_javascripts.js' + '?' + Math.floor (Math.random () * 10001);
Mirek Komárek,

La risposta di Alex non funzionerà se la versione cdn non viene caricata, perché il browser eseguirà questa condizione e durante il download continuerà a scaricare il resto dei javascript che richiedono jquery e restituisce errore -> I file JavaScript scaricati bloccheranno l'esecuzione del prossimo pezzo di codice quindi non è un problema .
alex,

2

Quasi tutti i CDN pubblici sono abbastanza affidabili. Tuttavia, se sei preoccupato per il dominio Google bloccato, puoi semplicemente eseguire il fallback a un CDN jQuery alternativo . Tuttavia, in tal caso, potresti preferire farlo in modo opposto e utilizzare qualche altra CDN come opzione preferita e fallback a Google CDN per evitare richieste non soddisfatte e tempi di attesa:

<script src="https://pagecdn.io/lib/jquery/3.2.1/jquery.min.js"></script>
<script>
   window.jQuery || document.write('<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"><\/script>');
</script>

1

Utilizzando la sintassi Razor in ASP.NET, questo codice fornisce supporto fallback e funziona con una radice virtuale:

@{var jQueryPath = Url.Content("~/Scripts/jquery-1.7.1.min.js");}
<script type="text/javascript">
    if (typeof jQuery == 'undefined')
        document.write(unescape("%3Cscript src='@jQueryPath' type='text/javascript'%3E%3C/script%3E"));
</script>

Oppure crea un aiutante ( panoramica dell'assistente ):

@helper CdnScript(string script, string cdnPath, string test) {
    @Html.Raw("<script src=\"http://ajax.aspnetcdn.com/" + cdnPath + "/" + script + "\" type=\"text/javascript\"></script>" +
        "<script type=\"text/javascript\">" + test + " || document.write(unescape(\"%3Cscript src='" + Url.Content("~/Scripts/" + script) + "' type='text/javascript'%3E%3C/script%3E\"));</script>")
}

e usalo così:

@CdnScript("jquery-1.7.1.min.js", "ajax/jQuery", "window.jQuery")
@CdnScript("jquery.validate.min.js", "ajax/jquery.validate/1.9", "jQuery.fn.validate")

Non mi sono mai preoccupato di Razor, ma sembra un offuscatore, tranne per il fatto che rende il codice più lungo piuttosto che più corto (è due volte più lungo di questo .
Maaartinus,

@maaartinus: non è un confronto mele-mele. La risposta di BenjaminRH, a cui ti riferisci, è per un singolo script ospitato dalla CDN. Con l' CdnScripthelper, è necessaria solo una riga di codice per script . Più script hai, più grande sarà il profitto.
Edward Brey,

Certo ... era solo uno sfogo. Tuttavia, suppongo che non sia il modo ottimale. Se qualcosa non dovesse funzionare, ignorerei completamente la CDN e passerei al fallback per tutti gli script. Non sono sicuro che ciò sia fattibile in quanto non so come funzioni esattamente il caricamento.
maaartinus,

@maaartinus: poiché ogni caricamento di script CDN può fallire in modo indipendente, è necessario controllare ciascun caricamento separatamente. Non esiste un metodo affidabile per un singolo controllo CDN seguito dal caricamento di tutti gli script da CDN a livello locale.
Edward Brey,

Il caso che mi preoccupa è un errore del sito CDN che porta a tempi di attesa per molti carichi. Quindi mi piacerebbe avere qualcosa del genere try { for (Script s : ...) cdnLoad(s); } catch (...) { for (Script s : ...) ownLoad(s); }. Tradurre questo in un mucchio di ifs potrebbe essere un incubo.
maaartinus,

1

Anche se la scrittura document.write("<script></script>")sembra più semplice per il backoff di jQuery, Chrome fornisce un errore di convalida in quel caso. Quindi preferisco rompere la parola "script". Quindi diventa più sicuro come sopra.

<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.1.min.js"></script>
<script>if (typeof jQuery === "undefined") {
   window.jqFallback = true;
   document.write("<scr"+"ipt src='http://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js'></scr"+"ipt>");
} </script>

Per problemi a lungo termine, sarebbe meglio registrare i fallback di JQuery. Nel codice sopra, se il primo CDN non è disponibile, JQuery viene caricato da un altro CDN. Ma potresti voler conoscere quel CDN errato e rimuoverlo permanentemente. (questo caso è un caso molto eccezionale) Inoltre è meglio registrare i problemi di fallback. Quindi puoi inviare casi errati con AJAX. Poiché JQuery non è definito, è necessario utilizzare javascript alla vaniglia per la richiesta AJAX.

<script type="text/javascript">
    if (typeof jQuery === 'undefined' || window.jqFallback == true) {
        // XMLHttpRequest for IE7+, Firefox, Chrome, Opera, Safari
        // ActiveXObject for IE6, IE5
        var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
        var url = window.jqFallback == true ? "/yourUrl/" : "/yourUrl2/";
        xmlhttp.open("POST", url, true);
        xmlhttp.send();
    }
</script>


0

Ancora un altro fallback che sostituisce ajax.googleapis.com con cdnjs.cloudflare.com :

(function (doc, $)
{
    'use strict';

    if (typeof $ === 'undefined')
    {
        var script = doc.querySelector('script[src*="jquery.min.js"]'),
            src = script.src.replace('ajax.googleapis.com', 'cdnjs.cloudflare.com');

        script.parentNode.removeChild(script);
        doc.write('<script src="' + src + '"></script>');
    }
})(document, window.jQuery || window.Zepto);
  • È possibile attenersi a una versione di jQuery specificandola nella stringa
  • Perfetto per la gestione patrimoniale che non funziona con i tag HTML
  • Testato in natura - funziona perfettamente per gli utenti dalla Cina

Potresti approfondire la seguente dichiarazione: "Non devi preoccuparti della versione di jQuery"?
Josh Habdas,

La versione fa parte dell'URL che non è adatto a essere toccato da questo approccio ... jquery / 3.xx / jquery.min.js
redaxmedia

1
Questo ha il potenziale per causare la rottura quando jQuery passa alla versione 4 e introduce modifiche incompatibili all'indietro?
Josh Habdas,

-1 perché ciò causerà la rottura se jQuery introduce delle modifiche non ancora supportate dagli script, a meno che non sia stata specificata la versione.
Lookaji,

@lookaji Penso che tu non capisca il fallback. Sostituisce il dominio in cui è ospitato e NON tocca affatto il nome file / versione.
redaxmedia,

0

Puoi usare il codice come:

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>window.jQuery || document.write('<script type="text/javascript" src="./scripts/jquery.min.js">\x3C/script>')</script>

Ma ci sono anche librerie che puoi usare per impostare diversi fallback possibili per i tuoi script e ottimizzare il processo di caricamento:

  • basket.js
  • RequireJS
  • yepnope

Esempi:

basket.js Penso che la variante migliore per ora. Memorizzerà la cache dello script nel localStorage, accelerando i caricamenti successivi. La chiamata più semplice:

basket.require({ url: '/path/to/jquery.js' });

Questo restituirà una promessa e puoi fare la prossima chiamata in caso di errore o caricare le dipendenze in caso di successo:

basket
    .require({ url: '/path/to/jquery.js' })
    .then(function () {
        // Success
    }, function (error) {
        // There was an error fetching the script
        // Try to load jquery from the next cdn
    });

RequireJS

requirejs.config({
    enforceDefine: true,
    paths: {
        jquery: [
            '//ajax.aspnetcdn.com/ajax/jquery/jquery-2.0.0.min',
            //If the CDN location fails, load from this location
            'js/jquery-2.0.0.min'
        ]
    }
});

//Later
require(['jquery'], function ($) {
});

yepnope

yepnope([{
  load: 'http://ajax.aspnetcdn.com/ajax/jquery/jquery-2.0.0.min.js',
  complete: function () {
    if (!window.jQuery) {
      yepnope('js/jquery-2.0.0.min.js');
    }
  }
}]);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.