La mejor manera de usar jQuery alojado en Google, pero recurrir a mi biblioteca alojada en Google falla

1016

¿Cuál sería una buena manera de intentar cargar jQuery alojado en Google (u otras bibliotecas alojadas en Google), pero cargar mi copia de jQuery si falla el intento de Google?

No digo que Google sea escamoso. Hay casos en los que la copia de Google está bloqueada (aparentemente en Irán, por ejemplo).

¿Configuraría un temporizador y buscaría el objeto jQuery?

¿Cuál sería el peligro de que salgan ambas copias?

En realidad, no estoy buscando respuestas como "solo usa Google" o "solo usa la tuya". Entiendo esos argumentos. También entiendo que es probable que el usuario tenga en caché la versión de Google. Estoy pensando en retrocesos para la nube en general.


Editar: Esta parte agregó ...

Dado que Google sugiere usar google.load para cargar las bibliotecas ajax, y realiza una devolución de llamada cuando termine, me pregunto si esa es la clave para serializar este problema.

Sé que suena un poco loco. Solo estoy tratando de averiguar si se puede hacer de manera confiable o no.


Actualización: jQuery ahora alojado en el CDN de Microsoft.

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

Nosredna
fuente
99
Por supuesto, la primera respuesta fue "no use la versión alojada de Google". :-)
Nosredna
77
Por supuesto, fue porque si desea alojar un sitio web serio, no confíe en que otra persona aloje sus archivos.
Bryan Migliorisi
66
@Bryan Migliorisi, ¿supongo que Twitter no es tan serio después de todo? Pero admito que tuvieron sus problemas con Google como hace un mes cuando Google dejó de funcionar.
Ionuț G. Stan
18
Los méritos de usar Google o no para el alojamiento de JS lib son dignos, pero se ha discutido en varios otros hilos. Estaba buscando respuestas técnicas con respecto a la reserva de JS en los retrasos de carga.
Nosredna
2
@ Joe Chung: es probable que se almacene en caché en el sistema del usuario, lo que acelerará la carga de la página. Me ahorra ancho de banda. Utiliza el CDN de Google. Etc.
Nosredna

Respuestas:

810

Puedes lograrlo así:

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

Esto debe estar en su página <head>y cualquier controlador de eventos listo para jQuery debe estar en el <body>para evitar errores (¡aunque no es infalible!).

Una razón más para no usar jQuery alojado en Google es que en algunos países, el nombre de dominio de Google está prohibido.

Rony
fuente
35
¿Ya no están bloqueando las descargas de JavaScript (sincrónico)? Me parece que el problema de la doble copia no sería un problema.
Matt Sherman
68
Las descargas de Javascript ya deberían estar sincronizadas, como dijo Matt Sherman. De lo contrario, se producirían muchos problemas si la página intentara ejecutar una secuencia de comandos en línea que se basara en una biblioteca que solo estaba medio descargada, o si se ejecutara una extensión de biblioteca sin la biblioteca completamente descargada y ejecutada. Esa es también una razón por la cual Yahoo YSlow recomienda colocar javascript al final de las páginas; para que no bloquee la descarga de otros elementos de la página (incluidos estilos e imágenes). Como mínimo, el navegador tendría que retrasar la ejecución para que se produzca secuencialmente.
gapple
42
Pequeña corrección de un fanático del validador: la cadena '</' no está permitida en JavaScript, porque podría malinterpretarse como el final de la etiqueta del script (notación de etiqueta corta SGML). Haga '<' + '/ script>' en su lugar. Saludos,
Boldewyn
8
Este ejemplo no funcionará. 1) si la biblioteca de Google ajax no está disponible, primero deberá agotar el tiempo de espera antes de fallar. Esto puede tardar un rato. En mi prueba de desconectar mi computadora de la red, simplemente intenté y probé y probé y no se agotó el tiempo de espera. 2) si (! JQuery) arrojará un error porque jQuery no está definido, por lo que Javascript no sabe qué hacer con él.
RedWolves
32
Para probar si jQuery se cargó, (! Window.jQuery) funciona bien y se acorta el tipo de verificación.
Jörn Zaefferer
335

La forma más fácil y limpia de hacer esto con diferencia:

<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
fuente
1
@jpp no ​​es para XHTML 1.0yHTML 4.01
BenjaminRH
55
La gente sigue pidiéndome que elimine las type="text/javascript"partes, así que para las personas que escriben html para navegadores antiguos, tengan en cuenta que ahora tendrán que agregar eso.
BenjaminRH
66
@BenjaminRH: también type="text/javascript"era innecesario en los navegadores más antiguos, ya que todos estaban predeterminados en Javascript. Los navegadores realmente más antiguos observaron el languageatributo; pero incluso entonces, Javascript era el predeterminado si faltaba el atributo.
Martijn
1
@Martijn Pero me gustó la brillante insignia de validación :)
BenjaminRH
3
@Trojan Totalmente posible, solo apila las llamadas. Tenga en cuenta que en este punto está abriendo nuevos hosts de conexiones, por lo que la canalización de HTTP probablemente será más rápida. ... <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

Esto parece funcionar para mí:

<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 forma en que funciona es usar el googleobjeto que llama a http://www.google.com/jsapi carga en el windowobjeto. Si ese objeto no está presente, estamos asumiendo que el acceso a Google está fallando. Si ese es el caso, cargamos una copia local usando document.write. (Estoy usando mi propio servidor en este caso, use el suyo para probar esto).

También pruebo la presencia de window.google.load: también podría hacer una typeofcomprobación para ver si las cosas son objetos o funciones, según corresponda. Pero creo que esto funciona.

Aquí está solo la lógica de carga, ya que el resaltado de código parece fallar desde que publiqué toda la página HTML que estaba probando:

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

Aunque debo decir que no estoy seguro de que si esto es una preocupación para los visitantes de su sitio, deba jugar con la API de bibliotecas AJAX de Google .

Dato curioso : al principio intenté usar un bloque try..catch para esto en varias versiones, pero no pude encontrar una combinación tan limpia como esta. Me interesaría ver otras implementaciones de esta idea, simplemente como un ejercicio.

artlung
fuente
1
¿Cuál es la ventaja de usar google.load en esta situación, en lugar de cargar ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js directamente, como sugirió Rony? Supongo que cargarlo directamente también detecta problemas con las bibliotecas eliminadas (¿y si Google deja de servir JQuery 1.3.2?). Además, la versión de Rony nota problemas de red DESPUÉS de que se haya obtenido www.google.com/jsapi, especialmente cuando jsapi se ha cargado desde el caché. Es posible que deba usar la devolución de llamada google.load para estar seguro (o tal vez haya algún valor de retorno para incluir google.load en el if (..)).
Arjan
Si se está probando la presencia de Google.com, se podría realizar una llamada de red o se podría verificar la presencia del objeto "gatekeeper". Lo que estoy haciendo es verificar el objeto de Google y su función de "carga". Si ambos fallan, no google, y necesito la versión local. La versión de Rony en realidad ignora la URL www.google.com/jsapi por completo, por lo que no estoy seguro de por qué indica que se ha recuperado.
artlung
Al final, todo lo que se requiere es que se cargue la biblioteca jquery. Cualquier biblioteca de Google no es un requisito. En la respuesta de Rony, uno sabe con certeza si la carga desde Google (o el caché) tuvo éxito. Pero en su verificación para "if (window.google && window.google.load)", la biblioteca jquery todavía no está cargada. ¿La carga real de la biblioteca jquery no está validada?
Arjan
Ah, veo cómo causé la confusión. "La versión de Rony nota problemas de red DESPUÉS de que se haya obtenido www.google.com/jsapi" debería leer mejor: "Su versión no detecta problemas de red DESPUÉS de que se haya obtenido www.google.com/jsapi".
Arjan
2
Recientemente hemos cambiado a usar Google como nuestro host jQuery; Si recibimos informes de errores de usuarios bloqueados, utilizaré una variante de su respuesta para refactorizar nuestro código de cliente. ¡Buena respuesta!
Jarrod Dixon
30

Si tiene modernizr.js incrustado en su sitio, puede usar yepnope.js incorporado para cargar sus scripts de forma asincrónica, entre otros, jQuery (con respaldo).

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

Esto carga jQuery del Google-cdn. Luego se verifica si jQuery se cargó correctamente. Si no ("no"), se carga la versión local. También se cargan sus scripts personales: el "ambos" indica que el proceso de carga se inicia independientemente del resultado de la prueba.

Cuando todos los procesos de carga están completos, se ejecuta una función, en el caso 'MyApp.init'.

Personalmente, prefiero esta forma de carga asíncrona de scripts. Y como confío en las pruebas de características proporcionadas por modernizr cuando construyo un sitio, lo tengo incrustado en el sitio de todos modos. Entonces, en realidad no hay gastos generales.

Emanuel Kluge
fuente
2
Creo que te estás perdiendo el punto de la pregunta: ¿cómo harías para cargar el script moernizr desde un CDN?
George Filippakos
2
No puedo recomendar cargar Modernizr desde un CDN. Uno debería obtener la versión personalizada más pequeña de modernizr.com.
Emanuel Kluge
2
Entonces, esta opción obtiene +16, en comparación con las 500/200 + + que obtienen las otras opciones. Pero esto suena bastante bien. ¿No es popular debido a que confía en Modernizer? De todos modos, uso Modernizer en nuestro sitio, así que si esto es mejor que las otras respuestas, ¿alguien puede avisarme? Soy bastante nuevo en JQuery, por lo que se agradece la aclaración.
redfox05
2
Esta fue una muy buena opción en el momento de la respuesta, pero a partir de 2015, yepnope.jsestá en desuso. ver stackoverflow.com/questions/33986561/…
Obmerk Kronen
Modernizr fue creado para resolver problemas como esta pregunta. +1
Carlos Quijano
21

Aquí hay algunas soluciones excelentes, pero me gustaría ir un paso más allá con respecto al archivo local.

En un escenario en el que Google falla, debería cargar una fuente local, pero tal vez un archivo físico en el servidor no sea necesariamente la mejor opción. Menciono esto porque actualmente estoy implementando la misma solución, solo que quiero recurrir a un archivo local que se genera por una fuente de datos.

Mis razones para esto es que quiero tener algo de mente cuando se trata de realizar un seguimiento de lo que cargo de Google frente a lo que tengo en el servidor local. Si quiero cambiar las versiones, querré mantener mi copia local sincronizada con lo que estoy tratando de cargar desde Google. En un entorno donde hay muchos desarrolladores, creo que el mejor enfoque sería automatizar este proceso para que todo lo que uno tuviera que hacer fuera cambiar un número de versión en un archivo de configuración.

Aquí está mi solución propuesta que debería funcionar en teoría:

  • En un archivo de configuración de la aplicación, almacenaré 3 cosas: URL absoluta para la biblioteca, URL para la API de JavaScript y el número de versión
  • Escribir una clase que obtenga el contenido del archivo de la propia biblioteca (obtiene la URL de la configuración de la aplicación), la almacena en mi fuente de datos con el nombre y el número de versión
  • Escribir un controlador que extraiga mi archivo local de la base de datos y lo almacene en caché hasta que cambie el número de versión.
  • Si cambia (en la configuración de mi aplicación), mi clase extraerá el contenido del archivo según el número de versión, lo guardará como un nuevo registro en mi fuente de datos, luego el controlador se activará y servirá la nueva versión.

En teoría, si mi código está escrito correctamente, todo lo que tendría que hacer es cambiar el número de versión en la configuración de mi aplicación y luego ¡viola! Tiene una solución alternativa que está automatizada y no tiene que mantener archivos físicos en su servidor.

¿Qué piensan todos? Tal vez esto sea excesivo, pero podría ser un método elegante para mantener sus bibliotecas AJAX.

Bellota

Bellota
fuente
Si está haciendo todo ese trabajo solo para jQuery, entonces diría que es exagerado. Sin embargo, si ya tiene algunos de esos componentes en su lugar para otras partes de su aplicación (por ejemplo, si ya carga scripts desde una base de datos), entonces se ve bastante bien.
Michael Haren
1
+1 por ser exhaustivo y novedoso, aunque no estoy convencido de que el beneficio justifique el tiempo de desarrollo y la complejidad.
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);

}

Después de intentar incluir la copia de Google del CDN.

En HTML5, no necesita establecer el typeatributo.

También puedes usar...

window.jQuery || document.write('<script src="/libs/jquery.js"><\/script>');
alex
fuente
2
+1 se ve más limpio. hay un error tipográfico en la parte superior de menor importancia que no puedo borrar desde su menor ery dos soportes de cierre después de 'indefinido'
naveen
1
La primera opción evita la advertencia de Chrome[Violation] Avoid using document.write().
Bob Stein,
La primera opción, desafortunadamente, no parece cargarse sincrónicamente . La segunda opción lo hace .
Bob Stein
10

Es posible que desee utilizar su archivo local como último recurso.

Parece que a partir de ahora, la propia CDN de jQuery no es compatible con https. Si lo hizo, es posible que desee cargar desde allí primero.

Así que aquí está la secuencia: Google CDN => Microsoft CDN => Su copia local.

<!-- 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
fuente
¿Existe realmente la necesidad de más de una alternativa? si ambos están desconectados, el usuario esperará más de un minuto antes de ver su sitio
George Filippakos
1
Un script no tarda 1 minuto en fallar al cargar, lo hace.
Edward Olamisan
@ geo1701 y Edward, realmente no hay necesidad de un tercero. Incluso una alternativa aún no se ha demostrado confiable. Si la API de Google está inactiva, todavía no he visto ninguna garantía de que el primer intento falle en absoluto. Experimenté un caso en el que un CDN nunca se pudo cargar, impidiendo que la página se procesara, como se menciona aquí: stevesouders.com/blog/2013/03/18/http-archive-jquery/…
hexalys
6

Cargue condicionalmente la última versión / legacy de jQuery y respaldo:

<!--[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
fuente
Esto no es compatible con navegadores cruzados.
Josh Habdas
Josh, sí, lo es.
neiker
4

¡Aquí hay una gran explicación sobre esto!

¡También implementa retrasos de carga y tiempos de espera!

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

Stuart.Sklinar
fuente
Las respuestas de solo enlace no son útiles y se consideran de baja calidad. Considere copiar los bits relevantes en su respuesta, con la atribución, por supuesto, a la fuente.
random_user_name
@cale_b ¿Estás bromeando? Esta respuesta tiene más de 7 años, por lo que dicho comentario no tiene justificación.
Stuart.Sklinar
Sí, es una vieja respuesta. Aunque su sugerencia es válida. Las respuestas que son meramente enlaces en otros lugares son candidatos para su eliminación. Lector adicional: meta.stackoverflow.com/q/8259
Rob
Estoy totalmente de acuerdo, moderaría yo mismo con sugerencias, pero no tiene sentido decirlo 7 años después. Debería haber sido moderado así hace 7 años, no 7 años después.
Stuart.Sklinar
1
@ Stuart.Sklinar: si lo hubiera visto hace 7 años, lo habría hecho :) Me encontré aquí investigando y viendo esto por primera vez. Lamento frustrarte, creo que nuestro trabajo en SO es ser administradores del sitio, lo que a veces significa comentar, editar o mejorar viejas preguntas o respuestas ...
random_user_name
4

Para aquellas personas que usan ASP.NET MVC 5, agregue este código en su BundleConfig.cs para habilitar el CDN para 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
fuente
4

ACTUALIZACIÓN:
Esta respuesta resultó ser incorrecta. Por favor, vea los comentarios para la explicación real.


La mayoría de sus preguntas han sido respondidas, pero en cuanto a la parte final:

¿Cuál sería el peligro de que salgan ambas copias?

Ninguno realmente Perdería el ancho de banda, podría agregar algunos milisegundos descargando una segunda copia inútil, pero no hay ningún daño real si ambos salen adelante. Por supuesto, debe evitar esto utilizando las técnicas mencionadas anteriormente.

WhyNotHugo
fuente
55
En realidad, cargar jQuery dos veces puede causar muchos problemas, de acuerdo con esta pregunta .
ShadowCat7
¿Por qué no lo prueba usted mismo y carga manualmente la biblioteca jquery dos veces? entonces la respuesta será revelada.
luke_mclachlan
¿Por qué exactamente está tan mal? @ ShadowCat7 ¿puede ser más específico sobre los problemas que causa? El único problema que veo identificado explícitamente en la pregunta que ha vinculado es "borrar todos los complementos cargados previamente". Pero eso no debería aplicarse a cargar el mismo archivo jQuery dos veces seguidas, ¿verdad? Pregunto porque las otras soluciones aquí para el repliegue local son muy complicadas, y document.write es difamado como malvado en algunos lugares .
Bob Stein
2

Hice un Gist que debería cargar dinámicamente jQuery si aún no está cargado, y si la fuente falla, procede a fallos (unidos entre muchas respuestas): https://gist.github.com/tigerhawkvok/9673154

Tenga en cuenta que planeo mantener el Gist actualizado, pero no esta respuesta, ¡por lo que 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();
}
Philip Kahn
fuente
2

Google Hosted jQuery

  • Si le interesan los navegadores más antiguos, principalmente versiones de IE anteriores a IE9, esta es la versión de jQuery más compatible
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  • Si no te importa oldIE, este es más pequeño y más rápido:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

Plan de copia de seguridad / respaldo!

  • De cualquier manera, debe usar un recurso alternativo a local en caso de que Google CDN falle (poco probable) o esté bloqueado en una ubicación desde la cual sus usuarios acceden a su sitio (un poco más probable), como Irán o, a veces, China.
<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>

Referencia: http://websitespeedoptimizations.com/ContentDeliveryNetworkPost.aspx

Ryan
fuente
Tenga en cuenta que cargar scripts sobre protocolos inseguros abre un vector de ataque XSS.
Josh Habdas
2

Considero que debería escapar del último <a \ x3C en cadena. Cuando el navegador ve, considera que este es el final del bloque de secuencia de comandos (dado que el analizador HTML no tiene idea sobre JavaScript, no puede distinguir entre algo que solo aparece en una cadena y algo que en realidad está destinado a finalizar la secuencia de comandos elemento). Entonces, aparecer literalmente en JavaScript que está dentro de una página HTML causará (en el mejor de los casos) errores y (en el peor de los casos) será un gran agujero de seguridad.

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

O

if(!window.jQuery){

No funcionará si la versión de cdn no está cargada, porque el navegador se ejecutará en esta condición y durante la descarga del resto de javascripts que necesitan jQuery y devuelve un error. La solución fue cargar scripts a través de esa condición.

    <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
fuente
Encontré un problema al probar scripts en Google Chrome: el almacenamiento en caché. Entonces, para las pruebas locales, simplemente reemplace src en la sección else con algo como s.src = 'my_javascripts.js' + '?' + Math.floor (Math.random () * 10001);
Mirek Komárek
La respuesta de Alex no funcionará si la versión de cdn no se carga, porque el navegador se ejecutará en esta condición y durante la descarga del resto de javascripts que necesitan jquery y devuelve el error -> Los archivos JavaScript que se descargan bloquearán la ejecución del siguiente código así que no es un problema .
alex
2

Casi todos los CDN públicos son bastante confiables. Sin embargo, si le preocupa el dominio de google bloqueado, simplemente puede recurrir a un CDN de jQuery alternativo . Sin embargo, en tal caso, es posible que prefiera hacerlo de manera opuesta y usar alguna otra CDN como su opción preferida y recurrir a Google CDN para evitar solicitudes fallidas y tiempos de espera:

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

Usando la sintaxis Razor en ASP.NET, este código proporciona soporte alternativo y funciona con una raíz virtual:

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

O haga un ayudante ( descripción general del ayudante ):

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

y úsalo así:

@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
fuente
Nunca he corazón acerca de la maquinilla de afeitar, pero parece que un ofuscador, a excepción de que se hace el código más largo en vez de más corta (que es dos veces más que esto .
maaartinus
@maaartinus: Esa no es una comparación de manzanas con manzanas. La respuesta de BenjaminRH, a la que se refiere, es para un solo script alojado en CDN. Con el CdnScriptasistente, solo necesita una línea de código por secuencia de comandos . Cuantos más guiones tenga, mayor será la recompensa.
Edward Brey
Claro ... fue solo una queja. Sin embargo, supongo que esa no es la forma óptima. Si algo falla, ignoraría CDN por completo y cambiaría a la reserva para todos los scripts. No estoy seguro de si esto es factible ya que no sé cómo funciona exactamente la carga.
maaartinus
@maaartinus: Dado que cada carga de script CDN puede fallar de forma independiente, debe verificar cada carga por separado. No existe un método confiable de una sola verificación de CDN seguido de cargar todos los scripts de CDN vs. localmente.
Edward Brey
El caso que me preocupa es una falla del sitio CDN que lleva a tiempos de espera para muchas cargas. Entonces me gustaría tener algo así try { for (Script s : ...) cdnLoad(s); } catch (...) { for (Script s : ...) ownLoad(s); }. Traducir esto en un montón de ifs podría ser una pesadilla.
maaartinus
1

Aunque escribir document.write("<script></script>")parece más fácil para el back-end de jQuery, Chrome da un error de validación en ese caso. Así que prefiero romper la palabra "script". Entonces se vuelve más seguro como arriba.

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

Para problemas a largo plazo, sería mejor registrar las fallas de respaldo de JQuery. En el código anterior, si el primer CDN no está disponible, JQuery se carga desde otro CDN. Pero es posible que desee saber ese CDN erróneo y eliminarlo permanentemente. (este es un caso muy excepcional) También es mejor registrar problemas de reserva. Entonces puede enviar casos erróneos con AJAX. Debido a que JQuery no está definido, debe usar JavaScript de vainilla para la solicitud de 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
fuente
0

Otra alternativa que reemplaza 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);
  • Puede apegarse a una versión jQuery especificándola en la cadena
  • Perfecto para la gestión de activos que no funciona con fragmentos HTML
  • Probado en la naturaleza: funciona perfecto para usuarios de China
redaxmedia
fuente
¿Podría explicar la siguiente afirmación: "No tiene que preocuparse por la versión jQuery"?
Josh Habdas
La versión es parte de la URL que no va a ser tocada por este enfoque ... jquery / 3.xx / jquery.min.js
redaxmedia
1
¿Tiene eso el potencial de causar una rotura cuando jQuery revuelve a la versión 4 e introduce cambios incompatibles con versiones anteriores?
Josh Habdas
-1 porque eso provocará una rotura si jQuery introduce cambios importantes que sus scripts todavía no admitirán a menos que se especifique la versión.
Lookaji
@lookaji Creo que no entiendes la alternativa. Sustituye el dominio donde está alojado y NO toca el nombre de archivo / versión en absoluto.
redaxmedia
0

Puedes usar código como:

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

Pero también hay bibliotecas que puede usar para configurar varios posibles retrocesos para sus scripts y optimizar el proceso de carga:

  • basket.js
  • RequireJS
  • sipnope

Ejemplos:

basket.js Creo que la mejor variante por ahora. Guardará su script en el almacenamiento local, lo que acelerará las próximas cargas. La llamada más simple:

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

Esto devolverá una promesa y puede hacer la próxima llamada por error, o cargar dependencias en caso de éxito:

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

sipnope

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