Archivos de la Categoría: rendimiento

Rendimiento: YUI Compressor + ANT = Ficheros comprimidos

El post anterior trataba sobre la utilización de la herramienta ANT para concatenar varios ficheros y así reducir el número de peticiones que hacía nuestra página web para ser cargada.

Otro punto importante, es que la posibilidad de reducir el fichero concatenado a un fichero mucho menor. La reducción puede ser tal, que según que librerías pueden llegar a reducirse un 80% del total de su peso. Si estamos de aplicaciones de intranet, podemos estar hablando de reducir la carga de 1 Mb a 300 Kb, lo cual es una mejora sustancial.

En post bastante antiguos expliqué el uso de la compresión de ficheros js mediante el PHP. Esta técnica es muy cómoda para sitios pequeños, pero en el momento que el proyecto reciba muchas peticiones, este sistema se puede volver en nuestra contra ya que estamos sobrecargando el servidor con un trabajo extra que puede ser evitado.

La versión más óptima de enviar ficheros comprimidos es que estos ya lo estén y que el servidor web únicamente se encargue de servir esta petición. Para ello vamos a utilizar gran librería creada por los expertos en optimización web de Yahoo: YUI Compressor. Necesitamos descargarnos esta librería y utilizar el fichero jar que tenemos en la carpeta build. Para los que no sepáis Java, tranquilos, no es necesario. Únicamente vamos a configurar nuestro XML de Ant para que utilice dicha librería para comprimir nuestros ficheros javascript (esta técnica también es aplicable a ficheros CSS).

Para ello, agregaremos la siguiente porción de código XML a nuestro fichero creado en el anterior post:

Este grupo de tareas se llama comprimirFicheros y antes de ejecutarse, ejecutará de forma no paralela el grupo de tareas concatenarFicherosJs. Más adentro, se le define la carpeta dónde están ubicados los ficheros js y que ficheros queremos comprimir, en este caso, el fichero que hemos generado después de concatenar los ficheros del grupo de tareas concatenarFicherosJs. Luego aparecen un grupo de líneas que detallan que la ejecución de la librería y algunos argumentos que ésta precisa.  Y por último no menos importante, se define que todos los ficheros js seleccionados para ser comprimidos, tendrán una copia con el mismo nombre pero acabado en -min.js.

<target name="comprimirFicheros" depends="concatenarFicherosJs">
<apply executable="java" parallel="false">
<fileset dir="js/" includes="fichero.js"/>
<arg line="-jar"/>
<arg path="yuicompressor.jar"/>
<srcfile />
<arg line="-o"/>
<mapper type="glob" from="*.js" to="js/*-min.js"/>
<targetfile />

Así, cuando hemos ejecutado este grupo de tareas, se ha ejecutado otro grupo (concatenarFicherosJs) y se ha generado un fichero comprimido del fichero generado por el grupo anterior (fichero-min.js). En este caso la reducción es mínima ya que son ficheros muy pequeños, pero si hacéis pruebas con ficheros más grandes, podréis comprobar la gran mejora sobre el peso del fichero que provoca la compresión con esta utilidad.

Esto debe ser un MUST, como dicen los anglosajones, dentro de nuestras técnicas para mejorar el rendimiento de nuestro sitio web.

Rendimiento: concatenando ficheros con ANT, reduciendo peticiones

Uno de los puntos primordiales en el rendimiento de la web es la reducción del número de peticiones que ésta realiza al servidor para cargar todos los elementos. A más peticiones, más tarda la página en cargar. Es cierto que podemos utilizar un CDN para cargar los ficheros necesarios de nuestra web desde diferentes servidores y con ello aumentar el rendimiento, pero esto es un añadido, no una mejora esencial.

Dentro de este tema de reducir las peticiones, aparece un tema recurrente en prácticamente todo proyecto web que se precie: la llamada a múltiples ficheros js para cargar una página web. Normalmente, nuestra página cuenta con algún framework javascript, cómo jQuery, el uso de algún plugin de este framework que estamos utilizando y por último, nuestro propio fichero js con javascript que hemos manufacturado nosotros. Es decir, de inicio, ya tenemos como mínimo tres peticiones. Veamos cómo podemos reducir el número de peticiones de 3 a 1.

Para ello, haremos uso de Ant. Para quien no lo conozca, es una herramienta que permite realizar tareas mecánicas, normalmente muy utilizada en proyectos Java. Las tareas se definen en ficheros xml que dicha herramienta interpreta. Entornos de desarrollo como Netbeans o Eclipse, llevan integrado esta utilidad. Veamos el siguiente xml:

< ?xml version="1.0" encoding="UTF-8"?>
<project name="DemoJavascript" xmlns:rsel="antlib:org.apache.tools.ant.types.resources.selectors">
<target name="concatenarFicherosJs" description="Unir varios ficheros js en orden">
<concat destfile="js/fichero.js">
<filelist dir="js/">
<file name="ficheroUno.js" />
<file name="ficheroDos.js" />
<file name="ficheroTres.js" />
</filelist>
</concat>
</target>
</project>

Lo primero que se define es un nombre del proyecto más el xlmns de Apache Ant, lo cual nos sirve para validar nuestra sintaxis dentro del fichero xml.

Luego definimos un grupo de tareas – target (nuestro fichero puede contener más de  un grupo de tareas) y la llamamos concatenarFicherosJs. Este grupo tiene una tarea llamada concat la cual indica que se deben concatenar ficheros. Esta tarea, define un atributo destfile que indica el fichero que contendrá los tres ficheros concatenados. Ya hemos indicado que queremos concatenar y en dónde queremos guardar el fichero generado. Ahora nos queda indicar que ficheros y en que orden queremos que se concatenen. Eso se realiza mediante la definición de una lista de ficheros – filelist, dónde indicamos la ruta – dir – dónde encontrar los ficheros que a continuación definimos. A partir de ahí, definimos cada uno de los ficheros que queremos concatenar y en que orden necesitamos que se concatenen. El orden es importante ya que si primero si intenta cargar un plugin de jQuery sin que el framework se haya cargado antes, nos dará un error.

Para los que no han utilizado nunca Ant, hay muchos ejemplos sencillos en internet de cómo ejecutar tareas de Ant desde Eclipse y Netbeans.

Esto es todo. Ahora ya podemos modificar nuestra página para que en vez de realizar tres solicitudes, cargue un único fichero. En la utilización de proyectos mucho más complejos, esto puede ser una mejora sustancial ya que podemos reducir las peticiones de 8 o 9 a 1 o 2.

Javascript – rendimiento: generación de nuevo contenido

Gracias a la mejora que ha sufrido los motores de javascript de los navegadores y de la revolución que ha supuesto Ajax para el mundo del desarrollo web, cada vez se ha optado por generación del contenido sin la necesidad de recargar la página.

El problema, es que esta generación al vuelo, si no se hace bien, puede producir que nuestra página sufra grandes retardos e incluso a mucha gente le aparezca el contenido a golpes. Esto suele ser debido a que el contenido que se está generando, se está inyectando al DOM durante su proceso de creación. Esto provoca que recorramos continuamente al DOM. Veamos un ejemplo:

var accessDiv = document.getElementById('access');
for (var i = 0; i < 50; i++){
accessDiv.innerHTML += 'hola';
}

De siguiente forma, generamos el html y una vez generado, entonces lo introducimos en el DOM:

var html = '';
for (var i = 0; i < 50; i++){
html += 'hola';
}
document.getElementById('access').innerHTML = html;

Javascript – rendimiento: array.length

Seguimos con otro punto a tener en cuenta a la hora de mejorar el rendimiento de nuestro código javascript. Supongamos que queremos recorrer todo los elementos DIV de una determinada página.  Normalmente el código que haríamos sería el siguiente:

var elementosDiv = document.getElementsByTagName('div');
for (var i = 0; i <  elementosDiv.length; i++){
//Trabajar con el array elementosDiv[i]
}

En la variable elementosDiv guardamos un array con todos los elementos DIV que contiene en nuestra página. Después, vamos iterando sobre este array trabajamos con cada uno de los elementos que componen este array. El problema que tiene este código, es que la variable elementosDiv contiene un array de elementos vivos, es decir, contiene una referencia directa al objeto DOM de nuestra página. Si durante la ejecución del bucle se agrega un nuevo elemento DIV a la página, automáticamente elementosDiv.length valdrá lo que valía antes más uno. Esto nos indica que para cada iteración del bucle, nuestro código solicita que se cuenten cuantos elementos DIV tiene el objeto DOM, lo cual produce una gran carga al navegador.

Para evitar este comportamiento, es tan sencillo como guardar cuantos elementos DIV hay justo antes de comenzar con la iteración.

var elementosDiv = document.getElementsByTagName('div');
for (var i = 0, count = elementosDiv.length; i < count; i++){
//Trabajar con el array elementosDiv[i]
}

En este código, justo cuando se inicializa el bucle, se guarda en la variable count el número de elementos del array. De esta forma, ya no es necesario que en cada iteración del bucle se tenga que ir a contar el número de elementos DIV al objeto DOM.

Javascript – rendimiento: reduciendo los accesos al DOM

Programar aplicaciones fiables debe ser el objetivo de cualquier profesional dedicado a este mundo. El problema, es que a veces nos centramos tanto en la fiabilidad que perdemos de vista otros elementos como pueden ser la usabilidad, accesibilidad, y en el caso que tratamos en este post, el rendimiento. En la actualidad, el rendimiento, y sobretodo en internet, es un factor clave para que un proyecto pueda tener éxito.

En este primer post, vamos a ver un truco  muy sencillo para optimizar el rendimiento de nuestro código javascript y así conseguir una respuesta más rápida de nuestro navegador.

Suponemos el siguiente código:


   var start = new Date().getTime();
   for (var i = 0; i < 5000; i++){
      document.getElementById('s').value = i;
   }
   var elapsed = new Date().getTime() - start;
   console.log(elapsed);

Este código accederá 5000 veces a un objeto y le cambiará su valor. Si ejecutáis este código con el firebug, podréis el tiempo en milisegundos que tarda en ejecutar dicho código. Cada vez que itera en el bucle, debe acceder al DOM y recorrerlo buscando un elemento que tenga un identificador igual a ‘s’.

Optimizar este código es muy sencillo y únicamente debemos acceder una vez al dom y guardar el objeto en una variable.


   var start = new Date().getTime();
   var s = document.getElementById('s');
   for (var i = 0; i < 5000; i++){
      s.value = i;
   }
   var elapsed = new Date().getTime() - start;
   console.log(elapsed);

Y aún mejor, si no queremos realizar ningún tipo de animación, únicamente mostrar un valor después de un bucle, podemos asignarlo al final del proceso


  var start = new Date().getTime();
  var j;
  for (var i = 0; i < 5000; i++){
   //Aquí haríamos nuestro cálculo
   j = i;
  }
  document.getElementById('s').value = j;
  console.log(end.getTime() - start);