latest - La mejor forma de usar jQuery alojado en Google, pero no puedo volver a mi biblioteca alojada en Google
jquery ui (22)
¿Cuál sería una buena manera de intentar cargar la jQuery alojada en Google (u otras bibliotecas alojadas en Google), pero cargar mi copia de jQuery si falla el intento de Google?
No estoy diciendo que Google sea inusual. Hay casos en que la copia de Google está bloqueada (aparentemente en Irán, por ejemplo).
¿Configuraré un temporizador y verificaré el objeto jQuery?
¿Cuál sería el peligro de que ambas copias lleguen?
No busco respuestas como "solo usa Google one" o "solo usa las tuyas". Entiendo esos argumentos. También entiendo que es probable que el usuario tenga la versión de Google en caché. Estoy pensando en alternativas para la nube en general.
Editar: Esta parte añadida ...
Como Google sugiere usar google.load para cargar las bibliotecas ajax, y realiza una devolución de llamada cuando termina, 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 una manera confiable o no.
Actualización: jQuery ahora alojado en CDN de Microsoft.
Al usar la sintaxis de Razor en ASP.NET, este código proporciona soporte de respaldo 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 haz un ayudante ( resumen 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")
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/
Aunque escribir document.write("<script></script>")
parece más fácil para el retroceso de jQuery, Chrome da un error de validación en ese caso. Así que prefiero romper la palabra "script". Así se vuelve más seguro como el de 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 los fallbacks 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 caso es un caso muy excepcional) También es mejor registrar problemas de reserva. Así que puedes enviar casos erróneos con AJAX. Debido a que JQuery no está definido, debe usar javascript de vainilla para la solicitud 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>
Condicionalmente, cargue la última versión / legado de jQuery y el 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]-->
Considero que debería escapar el último <to / x3C en la cadena. Cuando el navegador ve, considera que esto es el final del bloque de secuencias de comandos (ya que el analizador HTML no tiene idea acerca de JavaScript, no puede distinguir entre algo que simplemente aparece en una cadena y algo que realmente está destinado a finalizar la secuencia de comandos). elemento). Por lo tanto, aparecer literalmente en JavaScript que está dentro de una página HTML causará errores (en el mejor de los casos) 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>
Debido al problema de la prohibición de Google, prefiero usar el cdn de Microsoft http://www.asp.net/ajaxlibrary/cdn.ashx
Es posible que desee utilizar su archivo local como último recurso.
Parece que desde ahora el propio CDN de jQuery no es compatible con https. Si lo hiciste, entonces querrás cargar desde allí primero.
Así que aquí está la secuencia: CDN de Google => CDN de Microsoft => 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>
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 objeto de google
que se carga en http://www.google.com/jsapi al objeto de la window
. Si ese objeto no está presente, suponemos 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, por favor use el suyo para probar esto).
También window.google.load
la presencia de window.google.load
. También podría hacer una comprobación de tipo para ver si las cosas son objetos o funciones, según corresponda. Pero creo que esto hace el truco.
Aquí está 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, debería estar jugando con la API de bibliotecas de AJAX de Google .
Dato curioso : inicialmente 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.
Hay algunas soluciones excelentes aquí, 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. Lo menciono porque actualmente estoy implementando la misma solución, solo quiero recurrir a un archivo local generado por un origen de datos.
Mis razones para esto es que quiero tener algo de mente cuando se trata de hacer un seguimiento de lo que cargo de Google en comparación con lo que tengo en el servidor local. Si quiero cambiar las versiones, quiero mantener mi copia local sincronizada con lo que estoy intentando 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 tenga que hacer sea 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: la URL absoluta para la biblioteca, la URL para la API de JavaScript y el número de versión
- Escriba una clase que obtenga el contenido del archivo de la propia biblioteca (obtenga la URL de la configuración de la aplicación), la almacene en mi fuente de datos con el nombre y el número de versión
- Escriba un controlador que saque mi archivo local de la base de datos y almacene en caché el archivo 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 activará y entregará 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? Quizás esto sea una exageración, pero podría ser un método elegante para mantener sus bibliotecas AJAX.
Bellota
Hice un Gist que debería cargar dinámicamente jQuery si aún no está cargado, y si la fuente falla, continúa con los fallbacks (unidas de muchas respuestas): https://gist.github.com/tigerhawkvok/9673154
Tenga en cuenta que planeo mantener el Gist actualizado pero no esta respuesta, ¡para 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();
}
La forma más fácil y limpia de hacerlo por mucho:
<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>
La incapacidad para cargar el recurso desde un almacén de datos externo más allá de su control es difícil. Buscar funciones faltantes es totalmente engañoso como un medio para evitar sufrir un tiempo de espera, como se describe aquí: http://www.tech-101.com/support/topic/4499-issues-using-a-cdn/
Otro fallo adicional 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);
- Puedes apegarte a una versión de jQuery especificándola en la cadena
- Perfecto para la gestión de activos que no funciona con recortes HTML
- Probado en la naturaleza - funciona perfecto para usuarios de China
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);
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 debería estar en el <head>
su página y cualquier controlador de eventos de jQuery ready debería 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.
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 puedes usar para configurar varios posibles fallbacks para tus scripts y optimizar el proceso de carga:
- basket.js
- RequireJS
- yepnope
Ejemplos:
basket.js creo que la mejor variante por ahora. Almacenará su script en el localStorage, que acelerará las próximas cargas. La llamada más sencilla:
basket.require({ url: ''/path/to/jquery.js'' });
Esto devolverá una promesa y puede hacer la próxima llamada en caso de 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 ($) {
});
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'');
}
}
}]);
Si tiene modernizr.js integrado en su sitio, puede usar el yepnope.js incorporado para cargar sus scripts de forma asíncrona, 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 desde el cdn de Google. Después se comprueba, si jQuery se cargó correctamente. Si no ("no"), se carga la versión local. También se cargan sus scripts personales: "ambos" indica que el proceso de carga se inicia independientemente del resultado de la prueba.
Cuando se completan todos los procesos de carga, 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, de todos modos lo tengo incorporado en el sitio. Así que en realidad no hay gastos generales.
ACTUALIZAR:
Esta respuesta resultó ser incorrecta. Por favor, vea los comentarios para la explicación real.
La mayoría de ustedes han respondido, pero en cuanto a la parte final:
¿Cuál sería el peligro de que ambas copias lleguen?
Ninguno en realidad Usted desperdiciaría el ancho de banda, podría agregar algunos milisegundos descargando una segunda copia inútil, pero no hay daño real si los dos llegan. Por supuesto, debe evitar esto utilizando las técnicas mencionadas anteriormente.
Google alojó jQuery
- Si te interesan los navegadores más antiguos, principalmente las versiones de IE anteriores a IE9, esta es la versión jQuery más compatible.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
- Si no te importa el 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 respaldo / respaldo!
- De cualquier manera, debe usar una alternativa a local en caso de que la CDN de Google falle (improbable) o esté bloqueada en una ubicación desde la que sus usuarios accedan a su sitio (algo 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
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 desde el CDN.
En HTML5, no es necesario establecer el atributo de type
.
También puedes usar...
window.jQuery || document.write(''<script src="/libs/jquery.js"><//script>'');
if (typeof jQuery == ''undefined'')) { ...
O
if(!window.jQuery){
No funcionará si la versión de cdn no está cargada, ya que el navegador ejecutará esta condición y durante la misma seguirá descargando el resto de los javascripts que necesitan jQuery y devuelven 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>
- Paso 1: ¿No se pudo cargar jQuery? (verifique la variable
jQuery
)
Cómo verificar una variable no definida en JavaScript
- Paso 2: Importar dinámicamente (el respaldo) el archivo javascript
¿Cómo incluyo un archivo JavaScript en otro archivo JavaScript?