La cuestión es que prácticamente nada es imposible con el tándem navejador-javascript, pero de nada sirve tener un ferrari si le echamos alcohol destilado de remolachas para que corra. Llega el momento de hacer buen código y que éste sea rápido. Vamos a ver cómo hacerlo desde el punto de vista de interfaces responsivas y ágiles.
Como dije en la segunda entrega, para la carga de una página la principal consideración a tener en cuenta es que el proceso de la UI del navegador es la responsable tanto de realizar los cambios en la interfaz de la página como de la ejecución de los javascripts y que mientras no se termine con la carga de la página no se procede a la carga de otros elementos como por ejemplo, las imágenes.
la regla general es que todos los cambios en la UI deben usar la información más actualizada o final para que sean aplicados.
100ms es el límite de usuario para percibir una aplicación como ágil.
Mejora de rendimiento de la UI
Mejoras en la carga de los javascripts
La carga de javascripts bloquea el refresco de la interfaz en la carga de páginas, de modo que en el momento que se llega a un tag de <script>, el proceso es:
refresco ui -> petición .js -> carga .js -> parse del .js -> ejecución del .js -> continua la carga de la páginaDe esta manera las primeras optimizaciones sencillas son
- Colocar los scripts al final de las páginas
- Reducir el número de scripts cargados en una página
La carga dinámica de scripts no es bloqueante, de modo que si se lanza la carga de forma dinámica, la interfaz de usuario sigue actualizándose mientras se hace la carga y el parse del .js en segundo plano.
La ejecución del script comienza inmediatamente después de terminar la carga y el parse del .js por lo que la temporización de la ejecución no está garantizada.
La técnica básica es:
function loadScript(url, callback) {Uso:
var script = document.createElement("script"), body = document.body;
script.type = "text/javascript";
if(callback) {
// Se llama al callback cuando se termine la carga del script.
if(script.readyState) { // IE <= 8
script.onreadystatechange = function () {
if(script.readyState == "loaded" ||
script.readystate == "complete") {
script.onreadystatechange = null;
callback();
}
};
} else { // Otros
script.onload = function () { callback(); };
}
}
script.url = url;
body.insertBefore(script, body.irstChild);
}
loadScript(“foo.js”, function () { alert(“Cargado!”); } );Técnica de scripts diferidos (defer)
Esta técnica está soportada por todos los navegadores menos Opera(?) desde versiones muy antiguas. Se usa la palabra clave defer dentro del tag script.
<script defer src=”foo.js”></script>Los scripts diferidos se descargan inmediatamente y se parsean en segundo plano, pero no se ejecutan hasta que no se ha finalizado con la actualización de la UI.
Aunque la ejecución se retrasa hasta el final, no se garantiza que los scripts se ejecuten en el mismo orden en distintos navegadores.
Técnica de scripts asíncronos (async)
Esta técnica está soportada por todos los navegadores menos Internet Explorer(?) y Opera(?) desde versiones muy antiguas. Se usa la palabra clave async dentro del tag script.
<script async src=”foo.js”></script>Los scripts asíncronos tienen un funcionamiento muy similar al de los scripts dinámicos ya que se descargan y parsean en segundo plano, pasando a ejecutarse en primer plano (bloqueando el refresco de la UI por lo tanto) inmediatamente según se termine su parseo.
Como consecuencia, el orden de ejecución de los scripts no tiene por qué mantenerse para scripts asíncronos.
Técnica de javascript no bloqueante
Un método de añadir código que bloquee la ejecución del ui-thread, es crear un repositorio de funciones para luego ir añadiendo funciones a medida que se va realizando la carga, para finalmente ejecutar las que hagan falta.
En el head, habría que incluir un script que define un objeto con un array de funciones (nuestro repositorio) en él:
<script> var myapp = { funciones: []; }; // Crea el objeto myapp</script>A medida que se va cargando la página, en vez de incluir código del tipo:
<script>alert("boo!");</script>lo que se hace es
<script>Para ejecutar todas las funciones que se han añadido al repositorio habría que hacer:
myapp.funciones.push(function () {
alert("boo!");
});
</script>
var l = myapp.funciones.length;
for(var i = 0, i < l; i++) {
myapp.funciones[i]();
}
No hay comentarios:
Publicar un comentario