Le meilleur moyen d'utiliser jQuery hébergé par Google, mais de revenir à ma bibliothèque hébergée sur Google échoue

1016

Quelle serait une bonne façon de tenter de charger la jQuery hébergée sur Google (ou d'autres bibliothèques hébergées par Google ), mais de charger ma copie de jQuery si la tentative de Google échoue?

Je ne dis pas que Google est floconneux. Il y a des cas où la copie de Google est bloquée (apparemment en Iran, par exemple).

Vais-je configurer une minuterie et vérifier l'objet jQuery?

Quel serait le danger que les deux copies passent?

Pas vraiment à la recherche de réponses comme «utilisez simplement celle de Google» ou «utilisez simplement la vôtre». Je comprends ces arguments. Je comprends également que l'utilisateur aura probablement la version Google en cache. Je pense aux solutions de rechange pour le cloud en général.


Edit: Cette partie a ajouté ...

Étant donné que Google suggère d'utiliser google.load pour charger les bibliothèques ajax et qu'il effectue un rappel une fois terminé, je me demande si c'est la clé pour sérialiser ce problème.

Je sais que ça semble un peu fou. J'essaie simplement de savoir si cela peut être fait de manière fiable ou non.


Mise à jour: jQuery désormais hébergé sur le CDN de Microsoft.

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

Nosredna
la source
9
Bien sûr, la première réponse était «n'utilisez pas la version hébergée par Google». :-)
Nosredna
7
Bien sûr, c'est parce que si vous voulez héberger un site Web sérieux, vous ne devez pas compter sur quelqu'un d'autre pour héberger vos fichiers.
Bryan Migliorisi
6
@Bryan Migliorisi, je suppose que Twitter n'est pas si sérieux après tout? Mais j'avoue qu'ils ont eu leurs problèmes avec Google comme il y a un mois lorsque Google est tombé en panne.
Ionuț G. Stan
18
Le mérite d'utiliser Google ou non pour l'hébergement de bibliothèques JS est digne, mais il a été discuté dans plusieurs autres discussions. Je cherchais des réponses techniques concernant le repli de JS sur les délais de chargement.
Nosredna
2
@Joe Chung: Il est susceptible d'être mis en cache sur le système de l'utilisateur, ce qui accélère le chargement des pages. Me sauve la bande passante. Utilise le CDN de Google. Etc.
Nosredna

Réponses:

810

Vous pouvez le réaliser comme ceci:

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

Cela devrait être dans votre page <head>et tous les gestionnaires d'événements prêts pour jQuery devraient être dans le <body>pour éviter les erreurs (bien que ce ne soit pas infaillible!).

Une autre raison de ne pas utiliser jQuery hébergé par Google est que dans certains pays, le nom de domaine de Google est interdit.

Rony
la source
35
Les téléchargements javascript ne sont-ils pas déjà bloqués (synchrones)? Il me semble que le problème de la double copie ne serait donc pas un problème.
Matt Sherman
68
Les téléchargements Javascript devraient déjà être synchrones, comme l'a dit Matt Sherman. Sinon, de nombreux problèmes se produiraient si la page tentait d'exécuter un script en ligne qui reposait sur une bibliothèque qui n'était qu'à moitié téléchargée, ou si une extension de bibliothèque était exécutée sans que la bibliothèque soit entièrement téléchargée et exécutée. C'est également une des raisons pour lesquelles Yahoo YSlow recommande de placer le javascript à la fin des pages; afin qu'il ne bloque pas le téléchargement d'autres éléments de page (y compris les styles et les images). À tout le moins, le navigateur devrait retarder l'exécution pour se produire séquentiellement.
gapple
42
Petit correctif d'un fanatique de validateur: la chaîne '</' n'est pas autorisée en JavaScript, car elle pourrait être mal interprétée comme la fin de la balise de script (notation de balise courte SGML). Faites plutôt '<' + '/ script>'.
Santé
8
Cet exemple ne fonctionnera pas. 1) si la bibliothèque Google ajax n'est pas disponible, elle devra d'abord expirer avant d'échouer. Cela peut prendre un peu de temps. Dans mon test de déconnexion de mon ordinateur du réseau, il a juste essayé et essayé et essayé et n'a pas expiré. 2) if (! JQuery) générera une erreur car jQuery n'est pas défini, donc Javascript ne sait pas quoi en faire.
RedWolves
32
Pour tester si jQuery a été chargé, (! Window.jQuery) fonctionne correctement et est court-circuité, puis le typeof check.
Jörn Zaefferer
335

La façon la plus simple et la plus propre de le faire de loin:

<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>
BenjaminRH
la source
1
@jpp pas pour XHTML 1.0etHTML 4.01
BenjaminRH
5
Les gens continuent de me demander de supprimer les type="text/javascript"parties, donc aux gens qui écrivent du HTML pour les anciens navigateurs, notez que vous devrez maintenant l'ajouter.
BenjaminRH
6
@BenjaminRH: type="text/javascript"était également inutile dans les anciens navigateurs, car ils étaient tous par défaut en Javascript. Les navigateurs vraiment plus anciens ont examiné l' languageattribut; mais même alors, Javascript était la valeur par défaut si l'attribut manquait.
Martijn
1
@Martijn Mais j'ai aimé le badge de validation brillant :)
BenjaminRH
3
@Trojan Totalement possible, il suffit d'empiler les appels. Notez qu'à ce stade, vous ouvrez de nouveaux hôtes de connexion, donc le pipelining HTTP sera probablement plus rapide. ... <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
76

Cela semble fonctionner pour moi:

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

La façon dont cela fonctionne consiste à utiliser l' googleobjet que l'appel http://www.google.com/jsapi charge sur l' windowobjet. Si cet objet n'est pas présent, nous supposons que l'accès à Google échoue. Si tel est le cas, nous chargeons une copie locale à l'aide de document.write. (J'utilise mon propre serveur dans ce cas, veuillez utiliser le vôtre pour le tester).

Je teste également la présence de window.google.load- je pourrais également faire une typeofvérification pour voir que les choses sont des objets ou des fonctions appropriées. Mais je pense que cela fait l'affaire.

Voici juste la logique de chargement, car la mise en évidence du code semble échouer depuis que j'ai posté la page HTML entière que je testais:

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

Bien que je doive dire, je ne suis pas sûr que si cela préoccupe les visiteurs de votre site, vous devriez jouer avec l' API Google AJAX Libraries .

Fait amusant : j'ai d'abord essayé d'utiliser un bloc try..catch pour cela dans différentes versions, mais je n'ai pas pu trouver une combinaison aussi propre que celle-ci. Je serais intéressé de voir d'autres implémentations de cette idée, purement comme un exercice.

artlung
la source
1
Quel est l'avantage d'utiliser google.load dans cette situation, plutôt que de charger ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js directement, comme l'a suggéré Rony? Je suppose que le charger directement attrape également les problèmes avec les bibliothèques supprimées (et si Google cesse de servir JQuery 1.3.2). De plus, la version de Rony remarque des problèmes de réseau APRÈS que www.google.com/jsapi a été récupéré, en particulier lorsque jsapi a été chargé à partir du cache? On pourrait avoir besoin d'utiliser le rappel google.load pour être sûr (ou peut-être qu'il y a une valeur de retour pour inclure le google.load dans le if (..)).
Arjan
Si l'on teste la présence de Google.com, on pourrait passer un appel réseau, ou on pourrait vérifier la présence de l'objet "gatekeeper". Ce que je fais, c'est vérifier l'objet google et sa fonction "charger". Si les deux échouent, pas de google et j'ai besoin de la version locale. La version de Rony ignore en fait l'URL www.google.com/jsapi, donc je ne sais pas pourquoi vous indiquez qu'elle aura été récupérée.
artlung
Au final, il suffit de charger la bibliothèque jquery. Aucune bibliothèque Google n'est obligatoire. Dans la réponse de Rony, on sait avec certitude si le chargement à partir de Google (ou du cache) a réussi. Mais dans votre vérification pour "if (window.google && window.google.load)", la bibliothèque jquery n'est toujours pas chargée. Le chargement réel de la bibliothèque jquery n'est pas validé?
Arjan
ah, je vois comment j'ai causé la confusion. "La version de Rony remarque des problèmes de réseau APRÈS que www.google.com/jsapi a été récupérée" devrait mieux lire: "Votre version ne remarque aucun problème de réseau APRÈS que www.google.com/jsapi a été récupérée".
Arjan
2
Nous avons récemment décidé d'utiliser Google comme hôte jQuery; si nous obtenons des rapports de bogues d'utilisateurs bloqués, j'utiliserai une variante de votre réponse pour refactoriser notre code client. Bonne réponse!
Jarrod Dixon
30

Si vous avez modernizr.js intégré sur votre site, vous pouvez utiliser le yepnope.js intégré pour charger vos scripts de manière asynchrone - entre autres jQuery (avec repli).

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();
    }
}]);

Cela charge jQuery à partir de Google-cdn. Ensuite, il est vérifié si jQuery a été chargé avec succès. Sinon ("non"), la version locale est chargée. Vos scripts personnels sont également chargés - les «deux» indiquent que le processus de chargement est initié indépendamment du résultat du test.

Lorsque tous les processus de chargement sont terminés, une fonction est exécutée, dans le cas 'MyApp.init'.

Personnellement, je préfère cette méthode de chargement de script asynchrone. Et comme je me fie aux tests de fonctionnalités fournis par modernizr lors de la construction d'un site, je l'ai quand même intégré au site. Il n'y a donc pas de frais généraux.

Emanuel Kluge
la source
2
Je pense que vous manquez le point de la question - comment feriez-vous pour charger le script moernizr à partir d'un CDN?
George Filippakos
2
Je ne peux pas recommander de charger Modernizr à partir d'un CDN. On devrait plutôt obtenir la plus petite version personnalisée de modernizr.com.
Emanuel Kluge
2
Cette option obtient donc +16, par rapport aux 500/200 + + que les autres options obtiennent. Mais cela semble assez bon. N'est-il tout simplement pas populaire en raison de sa dépendance à Modernizer? Il m'arrive quand même d'utiliser Modernizer sur notre site, donc si c'est mieux que les autres réponses, quelqu'un peut-il me le faire savoir? Je suis assez nouveau sur JQuery, donc une clarification est appréciée.
redfox05
2
C'était une très bonne option au moment de la réponse, mais en 2015, elle yepnope.jsest obsolète. voir stackoverflow.com/questions/33986561/…
Obmerk Kronen
Modernizr a été créé pour résoudre des problèmes comme cette question. +1
Carlos Quijano
21

Il existe d'excellentes solutions ici, mais j'aimerais aller plus loin en ce qui concerne le fichier local.

Dans un scénario où Google échoue, il devrait charger une source locale, mais peut-être qu'un fichier physique sur le serveur n'est pas nécessairement la meilleure option. J'en parle parce que j'implémente actuellement la même solution, seulement je veux revenir à un fichier local qui est généré par une source de données.

Mes raisons sont que je veux avoir une certaine tranquillité d'esprit quand il s'agit de garder une trace de ce que je charge de Google par rapport à ce que j'ai sur le serveur local. Si je veux changer de version, je veux garder ma copie locale synchronisée avec ce que j'essaye de charger depuis Google. Dans un environnement où il y a beaucoup de développeurs, je pense que la meilleure approche serait d'automatiser ce processus pour qu'il ne reste plus qu'à changer un numéro de version dans un fichier de configuration.

Voici ma solution proposée qui devrait fonctionner en théorie:

  • Dans un fichier de configuration d'application, je vais stocker 3 choses: l'URL absolue de la bibliothèque, l'URL de l'API JavaScript et le numéro de version
  • Écrire une classe qui obtient le contenu du fichier de la bibliothèque elle-même (obtient l'URL de la configuration de l'application), la stocke dans ma source de données avec le nom et le numéro de version
  • Écrivez un gestionnaire qui extrait mon fichier local de la base de données et met le fichier en cache jusqu'à ce que le numéro de version change.
  • Si cela change (dans la configuration de mon application), ma classe extraira le contenu du fichier en fonction du numéro de version, l'enregistrera en tant que nouvel enregistrement dans ma source de données, puis le gestionnaire démarrera et servira la nouvelle version.

En théorie, si mon code est écrit correctement, tout ce que je devrais faire est de changer le numéro de version dans la configuration de mon application puis l'alto! Vous disposez d'une solution de secours automatisée et vous n'avez pas besoin de conserver des fichiers physiques sur votre serveur.

Que pense tout le monde? C'est peut-être exagéré, mais cela pourrait être une méthode élégante pour maintenir vos bibliothèques AJAX.

Gland

Gland
la source
Si vous faites tout ce travail juste pour jQuery, alors je dirais que c'est exagéré. Cependant, si vous avez déjà certains de ces composants en place pour d'autres éléments de votre application (par exemple, si vous chargez déjà des scripts à partir d'une base de données), cela a l'air plutôt bien.
Michael Haren
1
+1 pour être complet et novateur, bien que je ne sois pas convaincu que l'avantage justifie le temps de développement et la complexité.
Cory House du
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);

}

Après avoir tenté d'inclure la copie de Google à partir du CDN.

En HTML5, vous n'avez pas besoin de définir l' typeattribut.

Vous pouvez aussi utiliser...

window.jQuery || document.write('<script src="/libs/jquery.js"><\/script>');
alex
la source
2
+1 semble plus propre. il y a une faute de frappe mineure en haut que je ne peux pas effacer puisque ses deux
minuscules
1
La première option évite l'avertissement Chrome[Violation] Avoid using document.write().
Bob Stein
Malheureusement, la première option ne semble pas se charger de manière synchrone . La deuxième option le fait .
Bob Stein
10

Vous voudrez peut-être utiliser votre fichier local en dernier recours.

Il semble que le propre CDN de jQuery ne prend pas en charge https. Si c'est le cas, vous voudrez peut-être d'abord charger à partir de là.

Voici donc la séquence: Google CDN => Microsoft CDN => Votre copie 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> 
Edward Olamisan
la source
Y a-t-il vraiment besoin de plus d'une solution de rechange? si les deux sont hors ligne, l'utilisateur attendra plus d'une minute avant de voir votre site
George Filippakos
1
Il ne faut pas 1 minute pour qu'un script ne se charge pas, n'est-ce pas?
Edward Olamisan
@ geo1701 et Edward, il n'y a vraiment pas besoin d'un troisième. Une seule solution de rechange n'a pas encore été prouvée fiable. Si l'API Google est en panne, je n'ai encore vu aucune garantie que la première tentative échouera. J'ai rencontré un scénario de cas où un CDN n'a jamais échoué à se charger, empêchant la page de s'afficher
hexalys
6

Charger conditionnellement la dernière version / héritée de jQuery et son remplacement:

<!--[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]-->
neiker
la source
Ce n'est pas compatible avec tous les navigateurs.
Josh Habdas
Josh, oui, ça l'est.
neiker
4

Voici une excellente explication à ce sujet!

Implémente également les délais de chargement et les délais d'attente!

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

Stuart.Sklinar
la source
Les réponses de lien uniquement ne sont pas utiles et sont considérées comme de faible qualité. Pensez à copier les bits pertinents dans votre réponse, avec attribution bien sûr à la source.
random_user_name
@cale_b Vous plaisantez? Cette réponse a plus de 7 ans, un tel commentaire est donc injustifié.
Stuart.Sklinar
Ouais, c'est une vieille réponse. Bien que leur suggestion soit valable. Les réponses qui ne sont que des liens ailleurs sont susceptibles d'être supprimées. Autres lecteurs: meta.stackoverflow.com/q/8259
Rob
Je suis totalement d'accord, je modérerais moi-même mes suggestions - mais il est inutile de le dire 7 ans plus tard. Il aurait dû être modéré comme ça il y a 7 ans, pas 7 ans plus tard.
Stuart.Sklinar
1
@ Stuart.Sklinar - si je l'avais vu il y a 7 ans, j'aurais :) Je me suis retrouvé ici à faire des recherches et à le voir pour la première fois. Désolé de vous frustrer - je pense que nos emplois sur SO doivent être les administrateurs du site, ce qui signifie parfois commenter, modifier ou améliorer d'anciennes questions ou réponses ...
random_user_name
4

Pour les personnes utilisant ASP.NET MVC 5, ajoutez ce code dans vos BundleConfig.cs pour activer le CDN pour 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);
Muhammad Rehan Saeed
la source
4

MISE À JOUR:
Cette réponse s'est avérée fausse. Veuillez voir les commentaires pour la vraie explication.


La plupart d'entre vous ont répondu, mais comme pour la dernière partie:

Quel serait le danger que les deux copies passent?

Pas vraiment. Vous perdriez de la bande passante, vous pourriez ajouter quelques millisecondes en téléchargeant une seconde copie inutile, mais il n'y a pas de réel préjudice si les deux arrivent. Vous devez bien sûr éviter cela en utilisant les techniques mentionnées ci-dessus.

WhyNotHugo
la source
5
En fait, charger jQuery deux fois peut causer beaucoup de problèmes, selon cette question .
ShadowCat7
pourquoi ne pas le tester vous-même et charger manuellement la bibliothèque jquery deux fois. alors la réponse sera révélée.
luke_mclachlan
Pourquoi est-ce si mal? @ ShadowCat7 pouvez-vous être plus précis sur les problèmes qu'il provoque? Le seul problème que je vois explicitement identifié dans la question que vous avez liée est «la suppression de tous les plugins précédemment chargés». Mais cela ne devrait pas s'appliquer au chargement du même fichier jQuery deux fois de suite, non? Je demande parce que les autres solutions ici au repli local sont tellement compliquées, et document.write est dénigré comme mauvais à certains endroits .
Bob Stein
2

J'ai créé un Gist qui devrait charger dynamiquement jQuery s'il n'est pas déjà chargé, et si la source échoue, il passe aux solutions de rechange (assemblées à partir de nombreuses réponses): https://gist.github.com/tigerhawkvok/9673154

Veuillez noter que je prévois de garder le Gist à jour mais pas cette réponse, pour ce que ça vaut!

/* 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();
}
Philip Kahn
la source
2

Google Hosted jQuery

  • Si vous vous souciez des navigateurs plus anciens, principalement des versions d'IE antérieures à IE9, il s'agit de la version jQuery la plus compatible
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  • Si vous ne vous souciez pas de oldIE, celui-ci est plus petit et plus rapide:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

Plan de sauvegarde / repli!

  • Dans tous les cas, vous devez utiliser une solution de secours au niveau local juste au cas où le CDN Google échouerait (peu probable) ou serait bloqué dans un emplacement d'où vos utilisateurs accèdent à votre site (un peu plus probable), comme l'Iran ou parfois la Chine.
<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>

Référence: http://websitespeedoptimizations.com/ContentDeliveryNetworkPost.aspx

Ryan
la source
Notez que le chargement de scripts sur des protocoles non sécurisés ouvre un vecteur d'attaque XSS.
Josh Habdas
2

Je considère que cela devrait échapper au dernier <à \ x3C de la chaîne. Lorsque le navigateur le voit, il considère que c'est la fin du bloc de script (puisque l'analyseur HTML n'a aucune idée de JavaScript, il ne peut pas faire la distinction entre quelque chose qui apparaît simplement dans une chaîne et quelque chose qui est réellement destiné à mettre fin au script élément). Ainsi, apparaître littéralement en JavaScript à l'intérieur d'une page HTML provoquera (dans le meilleur des cas) des erreurs et (dans le pire des cas) constituera un énorme trou de sécurité.

<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>
JKhuang
la source
2
if (typeof jQuery == 'undefined')) { ...

Ou

if(!window.jQuery){

Ne fonctionnera pas si la version cdn n'est pas chargée, car le navigateur exécutera cette condition et pendant le téléchargement du reste des javascripts qui nécessitent jQuery et cela renvoie une erreur. La solution consistait à charger des scripts via cette condition.

    <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>
Mirek Komárek
la source
J'ai trouvé un problème dans les tests de scripts dans Google Chrome - la mise en cache. Donc, pour les tests locaux, remplacez simplement src dans la section else par quelque chose comme s.src = 'my_javascripts.js' + '?' + Math.floor (Math.random () * 10001);
Mirek Komárek
La réponse d'Alex ne fonctionnera pas si la version cdn n'est pas chargée, car le navigateur exécutera cette condition et pendant le téléchargement du reste des javascripts qui nécessitent jquery et renvoie une erreur -> les fichiers JavaScript téléchargés bloqueront l'exécution du morceau de code suivant ce n'est donc pas un problème .
alex
2

Presque tous les CDN publics sont assez fiables. Cependant, si vous vous inquiétez du domaine google bloqué, vous pouvez simplement revenir à un CDN jQuery alternatif . Cependant, dans un tel cas, vous pouvez préférer le faire de manière opposée et utiliser un autre CDN comme option préférée et revenir à Google CDN pour éviter les demandes échouées et le temps d'attente:

<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>
Hamid Sarfraz
la source
1

À l'aide de la syntaxe Razor dans ASP.NET, ce code fournit une prise en charge de secours et fonctionne avec une racine virtuelle:

@{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>

Ou créez une aide ( aperçu de l'aide ):

@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>")
}

et utilisez-le comme ceci:

@CdnScript("jquery-1.7.1.min.js", "ajax/jQuery", "window.jQuery")
@CdnScript("jquery.validate.min.js", "ajax/jquery.validate/1.9", "jQuery.fn.validate")
Edward Brey
la source
Je n'ai jamais aimé Razor, mais il ressemble à un obscurcisseur, sauf qu'il rend le code plus long que court (c'est deux fois plus long que cela .
maaartinus
@maaartinus: Ce n'est pas une comparaison de pommes à pommes. La réponse de BenjaminRH, à laquelle vous faites référence, concerne un seul script hébergé par CDN. Avec l' CdnScriptaide, vous n'avez besoin que d'une seule ligne de code par script . Plus vous avez de scripts, plus le gain est important.
Edward Brey
Bien sûr ... c'était juste une diatribe. Cependant, je suppose que ce n'est pas la façon optimale. Si quelque chose échoue, j'ignorerais complètement CDN et passerais à la solution de secours pour tous les scripts. Je ne sais pas si c'est faisable car je ne sais pas comment fonctionne exactement le chargement.
maaartinus
@maaartinus: Étant donné que chaque chargement de script CDN peut échouer indépendamment, vous devez vérifier chaque chargement séparément. Il n'y a pas de méthode fiable d'une seule vérification CDN suivie par le chargement de tous les scripts à partir de CDN vs localement.
Edward Brey
Le cas qui m'inquiète est une panne du site CDN entraînant des temps d'attente pour de nombreuses charges. Je voudrais donc avoir quelque chose comme try { for (Script s : ...) cdnLoad(s); } catch (...) { for (Script s : ...) ownLoad(s); }. Traduire cela en un tas de ifs pourrait être un cauchemar.
maaartinus
1

Bien que l'écriture document.write("<script></script>")semble plus facile pour le backoff de jQuery, Chrome donne une erreur de validation sur ce cas. Je préfère donc casser le mot "script". Il devient donc plus sûr comme ci-dessus.

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

Pour les problèmes à long terme, il serait préférable de consigner les solutions de repli JQuery. Dans le code ci-dessus, si le premier CDN n'est pas disponible, JQuery est chargé à partir d'un autre CDN. Mais vous pouvez vouloir connaître ce CDN erroné et le supprimer définitivement. (ce cas est un cas très exceptionnel) Il est également préférable de consigner les problèmes de secours. Vous pouvez donc envoyer des cas erronés avec AJAX. Étant donné que JQuery n'est pas défini, vous devez utiliser du vanilla javascript pour la demande 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>
trante
la source
0

Encore une autre solution de rechange qui remplace ajax.googleapis.com par 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);
  • Vous pouvez vous en tenir à une version jQuery en la spécifiant dans la chaîne
  • Parfait pour la gestion des actifs qui ne fonctionne pas avec les coupures HTML
  • Testé dans la nature - fonctionne parfaitement pour les utilisateurs de Chine
redaxmedia
la source
Pourriez-vous développer la déclaration suivante: "Vous n'avez pas à vous soucier de la version jQuery"?
Josh Habdas
La version fait partie de l'URL qui ne va pas être touchée par cette approche ... jquery / 3.xx / jquery.min.js
redaxmedia
1
Cela a-t-il le potentiel de provoquer une rupture lorsque jQuery passe à la version 4 et introduit des modifications incompatibles en arrière?
Josh Habdas
-1 car cela entraînera une rupture si jQuery introduit des modifications de rupture que vos scripts ne prendront pas en charge à moins que la version ne soit spécifiée.
Lookaji
@lookaji Je pense que vous ne comprenez pas le repli. Il remplace le domaine où il est hébergé et ne touche pas du tout au nom / version du fichier.
redaxmedia
0

Vous pouvez utiliser du code comme:

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

Mais il existe également des bibliothèques que vous pouvez utiliser pour configurer plusieurs solutions de rechange possibles pour vos scripts et optimiser le processus de chargement:

  • basket.js
  • RequireJS
  • yepnope

Exemples:

basket.js Je pense que la meilleure variante pour l'instant. Va mettre votre script en cache dans le localStorage, ce qui accélérera les prochains chargements. L'appel le plus simple:

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

Cela renverra une promesse et vous pouvez faire le prochain appel en cas d'erreur ou charger les dépendances en cas de succès:

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');
    }
  }
}]);
Роман Коптев
la source