Mar 182015
 
Artículo Administración de Servidores

El tiempo de carga de las páginas es un aspecto muy importante en la optimización de un sitio web. De entre los muchos aspectos que influyen en el tiempo total de carga de una página, la carga y ejecución del código javascript asociado puede ser en muchos casos uno de los más relevantes.

En este artículo examinamos las posibilidades técnicas que existen para reducir el impacto que esto supone.

Análisis del tiempo de carga de la página

Hay varias herramientas disponibles para analizar la contribución de los distintos elementos en el tiempo total de carga de la página. Una de ellas es Google PageSpeed Insights.

Para analizar una página con PageSpeed, basta con acceder a https://developers.google.com/speed/pagespeed/insights/, e introducir la URL que se desea analizar. Los resultados se presentan diferenciados para dispositivos móviles y equipos de sobremesa:

pagespeed-report-1

En el informe para equipos de sobremesa, la primera recomendación que se ofrece para mejorar el tiempo de carga de la página hace referencia al código javascript y CSS que bloquea la presentación de la parte superior de la página.

Si hacemos click sobre el enlace “Show how to fix”, se presenta un detalle de los elementos que provocan este bloqueo:

 

En este ejemplo, podemos ver que la página carga tres ficheros javascript que provocan el bloqueo.

  • En primer lugar, se carga la conocida librería jQuery.
  • A continuación,se carga la librería auxiliar jquery-migrate. Esta librería auxiliar es utilizada por los sitios que utilizan WordPress como CMS. Con ella, se asegura la compatibilidad con plugins desarrollados para versiones antiguas de la librería jQuery.
  • Por último, se carga un código javascript propio del sitio que estamos analizando.

El problema de la carga secuencial del código javascript

Para presentar una página en pantalla, el navegador debe descargar primero el código HTML de la página, y a continuación procesarlo. Pero, cada vez que se encuentra una referencia a un fichero javascript externo, procede a descargarlo y executarlo, antes de continuar el proceso del código HTML. Esto ocurre secuencialmente, de la siguiente manera:

Solución 1 – Mover las referencias a javascript externo  junto a la etiqueta </body>

Esta solución no disminuye el tiempo total de carga de la página, pero sí permite que todo el contenido HTML visible en la parte superior de la página se procese y se presente en pantalla antes de realizar la descarga del código javascript:

Al aplicar esta solución, puede aparecer un problema de dependencias si parte del código html de la página se genera utilizando llamadas a funciones que están definidas en la librería javascript externa.

Solución 2 – Utilizar el atributo “defer” en las referencias a javascript externo

Esta solución permite mantener en el header HTML las referencias al código javascript contenido en recursos externos. Con el atributo “defer”, aunque la descarga del fichero javascript se realiza al encontrarlo, la ejecución del mismo se realiza una vez que a terminado de procesarse el código HTML:

Al igual que en la primera solución, puede aparecer el problema de dependencias si hay código javascript “inline” en el código HTML de la página. Por lo demás, el atributo “defer” asegura que las librerías javascript descargadas se ejecutarán en el mismo orden en el que aparecen referenciadas en el código HTML.

Solución 3 – Utilizar el atributo “async” en las referencias a javascript externo

Si la referencia al código javascript incluye el atributo “async”, la descarga y ejecución del mismo se realiza en paralelo con la descarga y ejecución de otros recursos, y en paralelo con el proceso del código HTML de la página:

Como podemos ver, esta es la única solución que realmente reduce el tiempo total de descarga de la página, porque los recursos utilizados por la página pasan a ser descargados y procesados en paralelo, y no de una manera puramente secuencial.

Al igual que en las dos primeras soluciones, puede aparecer un problema de dependencias si hay código javascript “inline” que realiza llamadas a funciones que están definidas en los ficheros javascript.

Pero además, el problema se agrava porque no está garantizado que el código javascript descargado se ejecute en el mismo orden en que aparece referenciado en el código HTML de la página. En el ejemplo que hemos presentado más arriba, la librería “jquery-migrate.min.js” podría ser ejecutada por el navegador antes de haber ejecutado la librería “jquery.min.js”. Pero como el código javascript en “jquery-migrate.min.js” hace referencia a funciones y variables que se definen en “jquery.min.js”, se producirían errores.

Cómo solucionar el problema de las dependencias

En todos los casos, el problema de las dependencias debe resolverse añadiendo un código adicional al comienzo de cada librería, que compruebe que las librerías de las que depende han sido cargadas. En caso contrario, se utiliza la función setTimeout para reintentar la ejecución más tarde.

Tomemos como ejemplo el caso de una página que contiene código javascript “inline” que realiza una llamada a una función jQuery:

Este código presenta en pantalla el texto “Esto es un texto”, pero lo reemplaza inmediatamente por el texto “Hola mundo!”

Pero si ahora sustituimos la referencia a la librería jQuery para que ésta se cargue de manera asíncrona:

Al refrescar la pantalla veremos que el texto “Esto es un texto” permanece en pantalla. Examinando la consola javascript, comprobamos que se ha producido un error:

Para solucionarlo, introducimos el código javascript “inline” dentro de una función esperarJQuery(). La función comprueba si jQuery se ha cargado. Si es así, ejecuta el código. En caso contrario, la función se llama a sí misma para volver a ejecutarse al cabo de 100ms, recursivamente, hasta que comprueba que jQuery se ha cargado y está disponible:

Al recargar la página, podemos comprobar que el problema se ha resuelto y se vuelve a mostrar el texto “Hola mundo!” que se ha generado dinámicamente.

Ejecutar la librería “jquery-migrate” después de “jquery”.

En este caso, deberemos descargar la librería para tener una copia local en nuestro servidor. Por ejemplo, utilizando wget:

A continuación, editamos el fichero descargado, y utilizamos la misma técnica que hemos explicado anteriormente de “envolver” el código en una función recursiva:

Por último, deberemos modificar el código HTML de la página para que cargue la copia local modificada de jquery-migrate, y eso es todo!

 Publicado por en 1:00 pm

 Deja un comentario

(requerido)

(requerido)