PageSpeed OptiPic - optimización automática del sitio para los requisitos de Google Pagespeed Insights
JavaScript: Fusión, compresión, carga perezosa. CSS: compresión de tamaño y optimización de carga. Optimización de imágenes. Optimización de widgets de terceros y sistemas de análisis.

¿Es posible retrasar la carga de jQuery?

Afrontémoslo, jQuery/jQuery-ui es una descarga pesada.

Google recomienda la carga diferida de JavaScript para acelerar el rendimiento inicial. Mi página utiliza jQuery para configurar algunas pestañas que se colocan más abajo en la página (principalmente fuera de la vista inicial) y me gustaría diferir la carga de jQuery hasta DESPUÉS de que la página se haya renderizado.

El código de aplazamiento de Google agrega una etiqueta al DOM después de que la página se carga conectándose al evento onLoad del cuerpo:

<script type="text/javascript"> // Agregar un elemento de script como hijo del cuerpo función downloadJSAtOnload() { var element = document.createElement("script"); element.src = "deferredfunctions.js"; document.body.appendChild(element); } // Verificar si el navegador admite la capacidad de manejo de eventos if (window.addEventListener) window.addEventListener("load", downloadJSAtOnload, false); else if (window.attachEvent) window.attachEvent("onload", downloadJSAtOnload); else window.onload = downloadJSAtOnload; </script> 

Me gustaría diferir la carga de jQuery de esta forma, pero cuando lo intenté, mi código de jQuery no pudo encontrar jQuery (no completamente inesperado por mi parte):

$(document).ready(function() { $("#tabs").tabs(); }); 

Entonces, parece que necesito encontrar una forma de diferir la ejecución de mi código de jQuery hasta que jQuery se haya cargado. ¿Cómo detecto que la etiqueta agregada ha terminado de cargar e interpretar?

Como corolario, parece que la carga asíncrona también puede ser una respuesta.

¿Alguna idea?

#1

Prueba esto, que es algo que edité hace un tiempo desde el marcador jQuerify. Lo uso frecuentemente para cargar jQuery y ejecutar cosas después de que se haya cargado. Por supuesto, puedes reemplazar la URL allí con tu propia URL a tu versión personalizada de jQuery.

(function() { function getScript(url,success){ var script=document.createElement('script'); script.src=url; var head=document.getElementsByTagName('head')[0], done=false; script.onload=script.onreadystatechange = function(){ if ( !done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') ) { done=true; success(); script.onload = script.onreadystatechange = null; head.removeChild(script); } }; head.appendChild(script); } getScript('http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js',function(){ // AQUÍ VA TU CÓDIGO Y SE EJECUTA DESPUÉS DE QUE SE CARGUE JQUERY }); })();

Realmente combinaría jQuery y jQuery-UI en un solo archivo y usaría una URL hacia él. Si REALMENTE quisieras cargarlos por separado, simplemente encadenaría los getScripts:

getScript('http://miableajquery.js',function(){ getScript('http://miableajqueryUI.js',function(){ // tu código de pestañas aquí }) });
#2

Como esta es una pregunta de alto rango sobre un tema importante, permítanme atreverme a dar mi propia opinión sobre esto basada en una respuesta anterior de @valmarv y @amparsand.

Estoy utilizando un array multidimensional para cargar los scripts. Agrupando aquellos que no tienen dependencias entre ellos:

var dfLoadStatus = 0; var dfLoadFiles = [ ["http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"], ["http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js", "/js/somespecial.js", "/js/feedback-widget.js#2312195", "/js/nohover.js"] ]; function downloadJSAtOnload() { if (!dfLoadFiles.length) return; var dfGroup = dfLoadFiles.shift(); dfLoadStatus = 0; for(var i = 0; i<dfGroup.length; i++) { dfLoadStatus++; var element = document.createElement('script'); element.src = dfGroup[i]; element.onload = element.onreadystatechange = function() { if ( ! this.readyState || this.readyState == 'complete') { dfLoadStatus--; if (dfLoadStatus==0) downloadJSAtOnload(); } }; document.body.appendChild(element); } } if (window.addEventListener) window.addEventListener("load", downloadJSAtOnload, false); else if (window.attachEvent) window.attachEvent("onload", downloadJSAtOnload); else window.onload = downloadJSAtOnload; 

Carga primero jquery y después carga los otros scripts a la vez. Puedes añadir scripts fácilmente agregándolos al array en cualquier parte de tu página:

dfLoadFiles.push(["/js/loadbeforeA.js"]); dfLoadFiles.push(["/js/javascriptA.js", "/js/javascriptB.js"]); dfLoadFiles.push(["/js/loadafterB.js"]); 
#3

Aquí hay una buena descripción del enfoque moderno para cargar scripts de JavaScript con async/defer. Pero no funciona para scripts en línea

<script type="text/javascript" src="/jquery/3.1.1-1/jquery.min.js" defer></script> <script type="text/javascript" defer> $(function () { // <- jquery aún no se ha inicializado... }); </script> 

La solución más simple para la carga asíncrona fue sugerida por @nilskp: externalizar el script:

<script type="text/javascript" src="/jquery/3.1.1-1/jquery.min.js" defer></script> <script type="text/javascript" src="resources/js/onload.js" defer></script> 
#4

Agregué este fragmento de código después de la etiqueta del script de jquery async/defer, esto define una función temporal $ que acumulará todo lo que necesita ejecutarse cuando todo haya terminado de cargar, y luego, una vez que hayamos terminado, usa $ que en este momento se habrá sobrescrito para ejecutar las funciones. Con este fragmento de código no es necesario cambiar la sintaxis de carga de jQuery más abajo en el documento.

<script defer async src="https://code.jquery.com/jquery-2.2.0.min.js"> <script> var executeLater = []; function $(func) { executeLater.push(func); } window.addEventListener('load', function () { $(function () { for (var c = 0; c < executeLater.length; c++) { executeLater[c](); } }); }) </script> 

....y luego...

<script> $(function() { alert("cargado"); }); </script> 
#5
element.addEventListener("load", function () { $('#tabs').tabs() }, false); 

Prueba eso.

#6

Coloca jQuery y tu código dependiente de jQuery al final de tu archivo HTML.

Editar: Un poco más claro

<html> <head></head> <body> <!-- Tu contenido normal aquí --> <script type="text/javascript" src="http://ruta/a/jquery/jquery.min.js"></script> <script>//Coloca tu código jQuery aquí</script> </body> </html> 
#7

En ciertas situaciones, puedes activar un evento cuando se carga jQuery.

<script type="text/javascript"> (function (window) { window.jQueryHasLoaded = false; document.body.addEventListener('jqueryloaded', function (e) { console.log('jqueryloaded ' + new Date() ); }, false); function appendScript(script) { var tagS = document.createElement("script"), s = document.getElementsByTagName("script")[0]; tagS.src = script.src; s.parentNode.insertBefore(tagS, s); if ( script.id == 'jquery' ) { tagS.addEventListener('load', function (e) { window.jQueryHasLoaded = true; var jQueryLoaded = new Event('jqueryloaded'); document.body.dispatchEvent(jQueryLoaded); }, false); } } var scripts = [ { 'id': 'jquery', 'src': 'js/libs/jquery/jquery-2.0.3.min.js' }, { 'src': 'js/myscript1.js' }, { 'src': 'js/myscript2.js' } ]; for (var i=0; i < scripts.length; i++) { appendScript(scripts[i]); } }(window)); </script> 

Luego envuelve tus dependencias en una función:

// myscript1.js (function(){ function initMyjQueryDependency() { console.log('¡Mi código se ejecuta después de que jQuery se carga!'); // aquí va mi código que depende de jQuery } if ( jQueryHasLoaded === true ) initMyjQueryDependency(); else document.body.addEventListener('jqueryloaded', initMyjQueryDependency, false); }()); 

Si jQuery termina de cargarse después de los otros scripts, tus dependencias se ejecutarán cuando se active el evento jqueryloaded.

Si jQuery ya está cargado, jQueryHasLoaded === true, tu dependencia se ejecutará initMyjQueryDependency().

#8

Bueno, me parece que todo lo que tienes que hacer es a) agregar el código jQuery que quieres ejecutar al cargar al final del archivo de jQuery o b) agregarlo a la función downloadJSAtOnload de esta manera:

<script type="text/javascript"> // Agrega un elemento de script como hijo del body function downloadJSAtOnload() { var element = document.createElement("script"); element.src = "deferredfunctions.js"; document.body.appendChild(element); $("#tabs").tabs(); // <==== TEN EN CUENTA ESTO. Teóricamente, esto debería ejecutarse después de que el // script se haya agregado, aunque tendrás que probar esto // porque no sé si el JavaScript anterior esperará a que // el script se cargue antes de continuar } // Comprueba la compatibilidad del navegador con la capacidad de manejo de eventos if (window.addEventListener) window.addEventListener("load", downloadJSAtOnload, false); else if (window.attachEvent) window.attachEvent("onload", downloadJSAtOnload); else window.onload = downloadJSAtOnload; </script> 
#9

El siguiente código debería cargar sus scripts después de que la ventana haya terminado de cargarse:

<html> <head> <script> var jQueryLoaded = false; function test() { var myScript = document.createElement('script'); myScript.type = 'text/javascript'; myScript.async = true; myScript.src = jQueryLoaded ? 'http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.js' : 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js'; document.body.appendChild(myScript); if(!jQueryLoaded){ alert('jquery fue cargado'); jQueryLoaded = true; test(); } else { alert('jqueryui fue cargado'); } } if (window.addEventListener){ alert('window.addEventListener'); window.addEventListener("load", test, false); } else if (window.attachEvent){ alert('window.attachEvent'); window.attachEvent("onload", test); } else{ alert('window.onload'); window.onload = test; } </script> </head> <body> <p>Aquí va el texto de marcador de posición</p> </body> </html> 

Funcionó para mí en Chrome, FF e IE9 - avíseme si eso ayuda

#10

Aquí está mi versión que admite enlazar para asegurarse de que los scripts se carguen uno después de otro, basado en el código de ampersand:

var deferredJSFiles = ['jquery/jquery', 'file1', 'file2', 'file3']; function downloadJSAtOnload() { if (!deferredJSFiles.length) return; var deferredJSFile = deferredJSFiles.shift(); var element = document.createElement('script'); element.src = deferredJSFile.indexOf('http') == 0 ? deferredJSFile : '/js/' + deferredJSFile + '.js'; element.onload = element.onreadystatechange = function() { if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') downloadJSAtOnload(); }; document.body.appendChild(element); } if (window.addEventListener) window.addEventListener('load', downloadJSAtOnload, false); else if (window.attachEvent) window.attachEvent('onload', downloadJSAtOnload); else window.onload = downloadJSAtOnload; 
#11
<!doctype html> <html> <head> </head> <body> <p>Si haces clic en el botón "Ocultar", desapareceré.</p> <button id="hide" >Ocultar</button> <button id="show" >Mostrar</button> <script type="text/javascript"> function loadScript(url, callback) { var script = document.createElement("script") script.type = "text/javascript"; if (script.readyState) { //IE script.onreadystatechange = function() { if (script.readyState == "loaded" || script.readyState == "complete") { script.onreadystatechange = null; callback(); } }; } else { //Others script.onload = function() { callback(); }; } script.src = url; document.body.appendChild(script); } loadScript("http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js", function() { //YAHOO.namespace("mystuff"); $("#show").click(function() { $("p").show(); }); $("#hide").click(function() { $("p").hide(); }); //more... });  
#12

Creo que Modernizr.load() merece una mención aquí - maneja la carga de dependencias muy bien

#13

Hay un truco sencillo que utiliza Google Analytics.

Preparación

1. En la cabecera de tu HTML añade un pequeño script

<script> window.jQuery_store = []; window.jQueryReady = function (fn) { jQuery_store.push(fn); } </script> 

La función jQueryReady simplemente guarda delegados en un array para su uso futuro.

2. Crea un nuevo script JS jquery-ready.js con el siguiente contenido:

// Cuando jQuery esté listo $(function() { // Reemplaza la implementación anterior window.jQueryReady = function(fn) { // Llama inmediatamente a fn(); } // Llama a todos los callbacks guardados for (var i = 0; i < window.jQuery_store.length; ++i) { try { window.jQuery_store[i](); } catch (err) { console.log(err); } } }) 

Cuando se carga este script, hará lo siguiente:

  • Esperará hasta que sea seguro utilizar jQuery
  • Reemplazará la función jQueryReady por una nueva que llama al delegado inmediatamente (jQuery está listo en ese momento).
  • Iterará a través de las funciones guardadas de las llamadas anteriores a jQueryReady.

3. Une todo Haz que jquery-ready.js se cargue solamente después de que jQuery se haya cargado. En tu pie de página tendrás:

<script defer src=".../jquery.min.js"> <script defer src=".../bootstrap.min.js"> ... cualquier otro complemento para jQuery que probablemente necesites <script defer src=".../jquery-ready.js"> 

Esto se asegura de que el script jquery-ready.js se ejecutará solo después de que se haya ejecutado jQuery.

Uso

Ahora puedes utilizar la función jQueryReady cuando quieras.

jQueryReady(function() { // jQuery es seguro de usar aquí $("div.to-be-hidden").hide(); }) 
#14

Parece que solo necesitas <script defer> : http://www.w3schools.com/tags/att_script_defer.asp

#15

Echa un vistazo a jQuery.holdReady()

"Retiene o libera la ejecución del evento de jQuery ready." (jQuery 1.6+)

http://api.jquery.com/jQuery.holdReady/

#16

Quería cargar jQuery de manera diferida en un sitio de WordPress, por lo que no podía actualizar prácticamente todas las referencias que lo utilizan. En su lugar, escribí un pequeño envoltorio para encolar las llamadas de jQuery y llamarlas cuando finalmente se cargue. Colócalo en la cabeza del documento, solo ocupa alrededor de 250 bytes, y significa que jQuery puede cargarse de manera diferida o asíncrona sin modificar todas las referencias existentes. Mejoró significativamente el tiempo de carga.

Es posible que mi código rápido no funcione con todas las funciones de jQuery, pero hasta ahora ha funcionado con todo excepto una llamada a una función que he intentado. Normalmente, cuando hago cosas personalizadas, no las pongo a disposición, pero pensé en compartir este fragmento en línea. Disponible aquí: https://github.com/andrewtranter/jQuery_deferred_compat

#17

Carga todos los scripts al final del HTML con http://labjs.com, es una solución 100% y lo he probado muchas veces cumpliendo las reglas de gtmetrix. Ejemplo: http://gtmetrix.com/reports/interactio.cz/jxomHSLV

?