En uno de esos momento de querer pulir scripts en Javascript me pegó la neura de probar diferente formas de hacer lo mismo sacando el cronómetro y midiendo tiempos para ver que era más eficiente y que lo era menos.
Al final, por esas cosas del destino, me tuve que ir al final terminé olvidándome de lo que quería hacer. Hasta ahora que me he encontrado con esta presentación de Thomas Fuchs (author de Script.aculo.us). En ella (la recomiendo) hace exáctamente lo que yo quería hacer, medir los tiempos de ciertas tareas cotidianas y compararlas con alternativas que nos ofrece el mismo resultado.
Algunos de los resultados muestran cosas realmente interesantes:
Rendimiento
Objetos literales frente a clásicos
// Más lento
function literals(){
var a = [], o = {};
}
// Más rápido
function classic(){
var a new Array, o = new Object:
}
En la presentación se ven los resultados sobre los diferentes navegadores y podemos ver como de usar uno u otro en Google Chrome podemos multiplicar por 2 el tiempo de proceso.
Loops
Los loops tambien muestran unos resultados curiosos:
var test = '';
for (var i = 0; i<10000; i++)
test = test + str;
var test = '', i = 10000;
while(i--) test = test + str;
Entre los dos anteriores, no se muestran diferencias en los resultados devueltos.
// Más lenta
function normalLoop(){
var i = 60, j = 0;
while(i--) j++;
}
// Más rápida
function unrolledLoop(){
var j = 0;
j++; j++; j++; j++; j++; j++;
j++; j++; j++; j++; j++; j++;
j++; j++; j++; j++; j++; j++;
j++; j++; j++; j++; j++; j++;
j++; j++; j++; j++; j++; j++;
j++; j++; j++; j++; j++; j++;
j++; j++; j++; j++; j++; j++;
j++; j++; j++; j++; j++; j++;
j++; j++; j++; j++; j++; j++;
j++; j++; j++; j++; j++; j++;
}
Tambien vemos que muy caro hacer un loop, en Firefox multiplicamos por 2 el tiempo y en Google Chrome lo multiplicamos por 5.
Cachear variables globales
// Más rádida
function cache(){
var w = window, i = 10000;
while(i--) w.test = 'test';
}
// Más lenta
function nocache(){
var i = 10000;
while(i--) window.test = 'test';
}
El cachear variables globables nos ayudará en la mayoría de casos.
Acceder a atributos de un objeto frente a with()
// Más lento
function conwith(){
var obj = { prop: 'test', str: '' };
with(obj){
var i = 10000;
while(i--) str += prop;
return str;
}
}
// Más rápido
function sinwith(){
var obj = { prop: 'test', str: '' }, i = 10000;
while(i--) obj.str += obj.prop;
return obj.str;
}
En los resultados nos muestra que usar with() para acceder a un objeto nos puede penalizar el tiempo de proceso de nuestro Javascript. En el caso de Google Chrome reducimos el tiempo a un 7% del empleado con with().
Pasar a bits frente a parseInt()
// Más lenta
parseInt(12.50);
// Más rápida
~~(1 * "12.5");
Javascript 1.5 integra una serie de operadores a nivel de bit, entre ellos nos encontramos ~(Alt Gr + 4) que representa el NOT a nivel de bit y que en este caso nos ayuda a convertir a entero una cadena como podemos ver en el ejemplo (haciendo un doble NOT para obtener un valor positivo).
Curiosidades del lenguaje
Diferencia entre && y ||
var n = 1;
if (true && (n=2)) ...;
console.log(n);
// --> n = 2
if (true || (n=3)) ...;
console.log(n);
// --> n = 2
Como es lógico, el uso de && evalua las dos condiciones frente a || que si ya se cumple la primera, nos evitamos comprobar la segunda.
(...).toString()
(function(){ return 2 * 3; }).toString();
// IE, Safari y Google Chrome
function(){ return 2 * 3; }
// Firefox
function(){ return 6; }
En este ejemplo vemos como la ejecución de esta función anónima nos muestra un resultado algo extraño en Firefox.
Más info
- Extreme Javascript Perfomance (Thomas Fuchs)
- JsRocks