Contenido

La mejora manera de cargar javascript

31 jul

+ 26

Hace unos meses vimos algunas técnicas para cargar Javascript asincronamente y así evitar el bloqueo del navegador mientras se carga el fichero Javascript. El mayor problema que nos encontramos al cargar Javascript es que el navegador deja de renderizar la página mientras carga el fichero Javascript.

En cambio, si cargamos los ficheros dinámicamente mediante Javascript, evitamos el problema y podemos cargar ficheros Javascript de forma asíncrona sin afectar al renderizado de la página.

Nicholas C. Zakas, ha estado pensando sobre el tema y ha sacado 3 puntos imprescindibles a tener en cuenta para mejorar la carga del javascript de nuestras páginas.

  1. Crear dos ficheros Javascript. En el primero poner lo necesario para cargar dinámicamente otro ficheros javascript y el segundo con el código necesario para nuestra aplicación.
  2. Incluye el primer Javascript el final de la página, justo encima de </body>.
  3. Justo debajo creamos un segundo tag <script> en donde llamaremos al/los fichero/s necesarios.

Nuestro HTML quedaría más o menos así:

<script type="text/javascript" src="http://your.cdn.com/first.js"></script>
<script type="text/javascript">
loadScript("http://your.cdn.com/second.js", function(){
 //initialization code
});
</script>

loadScript()

loadScript() es la función encargada de cargar el fichero Javascript de forma dinámica y encargada de ejecutar el código que indiquemos como segundo parámetro en cuando este esté cargado correctamente.

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.getElementsByTagName("head")[0].appendChild(script);
}

Está claro que estas optimizaciones mejoran el resultado, aunque estamos hablando de milisegundos (o pocos segundos en el peor de los casos). Pero es bueno conocer formas de mejorar nuestros scripts y así pulirlos perfectamente.

  • Muy buen aporte Andrés.
    Gracias!!

  • Muy util sobre todo por lo de ejecutar el código al cargar, a favoritos, idoneo para hacer una barra de carga como la de tuenti/gmail.

    Yo antes usaba include de phpjs porque la verdad es que no tengo ni idea de js aunque vaya sobreviviendo, pero este me gusta mucho más.

    Ahora tengo una pregunta porque se me da bastante mal el js, si yo quisiera cargar varios ficheros uno a uno como sería?

    
    loadScript("script.js", function(){
     //initialization code
    });
    loadScript("script.js", function(){
     //initialization code
    });
    loadScript("script.js", function(){
     //initialization code
    });
    

    o:

    
    loadScript("script.js", function(){
     //initialization code
    loadScript("script.js", function(){
     //initialization code
    loadScript("script.js", function(){
     //initialization code
    });
    });
    });
    

    ?
    Gracias.

  • @jay: Pues depende de como lo quieras cargar. Ambas son correctas, en la primera se cargarán asíncronamente todas y en la segunda, una vez cargado la primera, llamará a la segunda y así las demás.

  • Sería mejor la segunda opción ¿no?

    Digo, si primero cargo JQuery y luego una función que lo usa, antes de ejecutarse debería estar ya el JQuery en memoria…

    ¿O es que el .ready se ejecuta cuando terminó de cargar todo el código de la página?

    Es mejor esta opción o la de include de phpjs?

  • @josepzin: Hombre, en ese caso si que es la forma correcta. Si necesitas jQuery, debes cargarlo previamente para poder usarlo.

    El .ready() en estos ejemplos no tiene mucho sentido ya que se está ejecutando al final del fichero y prácticamente todo está cargado ya cuando ejecutas el Javascript.

  • Esta solución es elegante pero tiene un problema con scripts que utilicen la sentencia document.write(‘contenido html desde javascript’) muy utilizada por servicios de anuncios.

    Ésta sentencia si se ejecuta de manera asíncrona, y el navegador acabó de renderizar el contenido de la página, provocará que el navegador inserte el nuevo contenido eliminando el anterior.

    Para solucionar este problema obté por emplear iframes con el contenido de los scripts de los banners. Hay otra técnica para sobreescribir el comportamiento de document.write y tener la posibilidad de cargar los scripts de forma asíncrona:
    http://subtlegradient.com/articles/2009/06/22/replace_document_write_using_mootools.html

  • Muy interesante el artículo.Ya no solo sirve para una carga más rapida de la página ,sino para realizar algunas funciones en el cuerpo de la página una vez cargada dicha página.

  • @aNieto2k: Gracias por la aclaración, supuse que pasaría algo así pero es que con js francamente nunca me siento comodo, ni con jquery.

    Ahora solo queda ver la velocidad de ambas, yo no voy a hacer un benchmark porque no creo que sea fiable ene mi equipo con tuneup, nod 32, megamanager, firefox con chorricientas pestañas abiertas, msn messenger, vlc, etc. no creo que los resultados sean fiables porque cualquier programa puede iniciar o parar una tarea secundaria como un analisis de av, desfragmentar, estar bajando de megamanager, etc. que te destrozan las pruebas.

    @josepzin: Como dije antes no se casi nada de js, se me da mal, que le vamos a hacer, pero ya la única diferencia que le veo es que el de phpjs se incluye y ya y este te permite realizar una función.

    Por otro lado supongo, repito, supongo que podrías hacer en el de phpjs podrás hacer:


    if ( include('script.js') ) { accion();}

    Si esto que digo funciona bien es muy interesante porque a diferencia de este supongo que puedes añadir un else por si no consigue cargar. Con este no se si se podrá.

    PD: Tu estabas en 3DA? Lastima que el 3d se me de aún peor que el javascript, me encantaba xD

    @vifito: No se si lo he entendido bien, pero me parece poco práctico hacer eso en lugar de innerHTML, creo que no es estándar pero lo soportan todos los navegadores y en html creo que pasa a ser válido. Respecto a la web si ese blog es tuyo, y no te importa una crítica creo que deberías hacer las letras un poco más grandes, se me hizo incomodo leerlo y tuve que hacer zoom.

  • jay: ¡Si! ¡Soy yo! Alguien me recuerda, mi vida tiene sentido! :D

    Yo tambien creo que el método de incluir con PHP creo que es mejor, ya que de una sola carga se incluyen todos los javascripts.

  • @josepzin: Coño Jose! como te va? sigues dandole al 3d y con eso de glest? bueno al tema xD, yo no tengo tan claro que sea mejor, si funciona

    if ( include('script.js') ) { accion();}

    es decir si el include devuelve un valor verdadero o falso (cosa que no tengo clara) y permite usar un else veo mejor el include.

    Sobre si permite cargar todos a la vez o no, si haces:


    loadScript("script.js", function(){
    //initialization code
    });
    loadScript("script.js", function(){
    //initialization code
    });
    loadScript("script.js", function(){
    //initialization code
    });

    (viva firebug XD)

    Te permite cargar todo a la vez de forma independiente, creo yo.

    PD: Si he dicho algo estúpido lo mio es el php/sql no el js T_T

  • Jay: parece que me recuerdas mas que bien!! :D
    Yo en cambio no te identifico… ¿tienes el mismo nick? Dame una pista :P

    Y no, he abandonado el 3D, de a poco y sin darme cuenta cada vez fueron mas páginas web, más programación PHP y menos 3D, asi que cuando me di cuenta estaba demasiado “oxidado”…

  • El nick era más o menos el mismo, jayjayjay_92 :P, si te sirve de consuelo, yo reconocí tu avatar de glest hace unas semanas y hoy me he dado cuenta de que conocía ese nick, por cierto, tu ves en php.js que el include devuelva true o false?

    Yo es que no acabo de entender el script (el js se me da de pena, al menos con jquery, chuleta en mano, voy haciendo algo…) veo que hace un return pero no veo si puede dar false o si se puede interpretar como true…

  • El problema que planteaba viene de la forma que tiene los sistemas de banners de embeber javascript dentro de javascript mediante document.write. Normalmente los sistemas como doubleclick, adsense, … proporcionan una referencia a un javascript que internamente contiene cosas como la siguiente y que no podemos modificar ya que se cargan desde dominios externos y con contenido aleatorio:

    {script type=”text/javascript”}
    document.write(‘{script src=”http://www.otrodominio.com/otro.js”}{/script}’);
    {/script}

    entendiendo la sintáxis {script} como tags de script

    P.D. el blog q referencié no es mio y es la única referencia que encontré para sobreescribir el comportamiento de document.write y que siga funcionando todo

  • Me he pasado varias veces por este blog, me ha ayudado mucho como no hay una sección en específico para agradecer tengo que hacertelo notar en este mensaje.

  • jay: sí, ahora te recuerdo, un pacer volver a verte :)

    Sobre el php, al final tiene un “return this.php_js.includes[filename];” que sinceramente no entiendo lo que hace… Parece devolver 1(TRUE) cuando todo ha ido bien… :?

    Ya la probaré a ver como funciona.

  • Muy interesante. Valdría la pena hacer un autoload js (Si aun no existe) similar al de PHP.
    Alguien sabe que diferencia hay entre esto y el $().getScript() de jQuery ?

  • Andrés, muchas gracias por tu referencia a nuestro blog. Y anhorabuena por tus explicaciones.

Comentar

#

Me reservo el derecho de eliminar y/o modificar los comentarios que contengan lenguaje inapropiado, spam u otras conductas no apropiadas en una comunidad civilizada. Si tu comentario no aparece, puede ser que akismet lo haya capturado, cada día lo reviso y lo coloco en su lugar. Siento las molestias.