Con páginas, y aplicaciones web, cada vez más pesadas, nos enfrentamos a un importante reto, que excede las capacidades iniciales de ECMAScript.

Me estoy refiriendo a la velocidad de visualización de las páginas. Por defecto, una página sólamente se renderiza cuando todas sus dependencias están disponibles, por lo que con tamaños que aumentan, cada vez es más complicado.

Cabe recordar, que cuando hacemos una inclusión de un archivo JS externo en nuestra página, lo que ocurre es que el navegador solicita la el archivo, lo ejecuta, y entonces continúa la carga de la página principal. Es lo que se llama Blocking Javascript, y que es como digo, el comportamiento por defecto, cuando hacemos algo como esto:

<script type="text/javascript" language="Javascript" src="miscript.js"></script>

No se trata de que carguen al completo de manera más rápida, ese sería otro tema, sino que solamente lo parezca, haciendo que la mayoría de contenido se visualice lo antes posible.

Antiguamente lo que se hacía, era mover todos los scripts que no era necesario tener durante la carga de la página, al final del body, así al menos, el HTML se visualizaba, y luego se ponían a cargar los Javascript.

Después, se empezó a hacer evaluando el include con el propio Javascript, de manera que hasta que terminaba de parsearse la página, no se generaba el include, y por tanto no se cargaba, de esta forma:

document.write('< ' + 'script src="miscript" type="text/javascript">< ' + '/script>');

Después se hacía esto mismo, pero creando el elemento en el DOM, en vez de con document.write, que causaba bastante deterioro en el rendimiento de JIT. Así:

function LoadScript(src, callback)
{
	var s, r, t;
	r = false;
	s = document.createElement('script');
	s.type = 'text/javascript';
	s.src = src;
	s.onload = s.onreadystatechange = function()
	{
		if (!r && (!this.readyState || this.readyState == 'complete'))
		{
			r = true;
			callback();
		}
	};
	t = document.getElementsByTagName('script')[0];
	t.parentNode.insertBefore(s, t);
}

Finalmente, aparecieron los atributos defer y async, que ayudaban a implentar esa carga no bloqueante de scripts (asíncrona), de forma nativa, claro está en los navegadores que la soportan.

En el caso de defer, es más compatible (IE 6, Firefox 3.5, Chrome 8, Safari 5, Opera 15), pero limita la carga y ejecución del código incluido, a cuando ha terminado de parsearse la página:

<script defer type="text/javascript" language="Javascript" src="miscript.js"></script>

Se puede usar async, que es más reciente (IE 10, Firefox 3.6, Chrome 8, Safari 5.1, Opera 15), y que permite que el código se cargue y ejecute en paralelo con la carga y renderizado de la página:

<script async type="text/javascript" language="Javascript" src="miscript.js"></script>

Claro que ninguno de estos sistemas es mágicos, si por ejemplo el código que cargamos depende de que determinados elementos del DOM estén cargados, no funcionará la asincronía, y puede que tampoco lo haga el evento onload, ya que el HTML puede estar cargado, pero el resto de dependencias aún no, de modo que no nos quedará más opción que interceptar los diferentes eventos soportados por diferentes navegadores, onload, onreadystatechange, load o DOMContentLoaded.

Parece que como en casi todo, mejorar el rendimiento nunca es fácil, ¡pero si divertido!

A este respecto, espero que hayáis notado alguna mejoría reciente en la carga de mi blog.