Programar Javascript eficientemente

Código sin errores

Puede parecer una obviedad, pero muchos programadores noveles cometen grandes errores de sintaxis en su código sin darse cuenta y, puesto que los intérpretes de javascript tienen cierta tolerancia a dichos errores, no se dan cuenta.

Dichos errores, aunque no frenen la ejecución en según que intérpretes, drenan en gran medida el rendimiento, y pueden convertir el algoritmo más eficiente del mundo en el código más lento jamás ejecutado.

// Errores comunes
var a = 5 // Omitir ;
b = 6; // No declarar variables apropiadamente
function c(){
return this; // this fuera de objetos (devolverá window)
}

Y por último un caso un poco complicado de entender.

var d = [ 1, 2, 3, 4, 5, 6 ], e = 0;
for( var f in d ){ e += f; }

La sintaxis for( x in y ) ejecuta el código dentro del bucle asignando a x todos y cada uno de los atributos de y. Es decir, en el caso anterior, no sólo recorrería todos los elementos del Array, sino sus métodos tales como splice, slice... o sus atributos como length. O al menos es así en intérpretes que respetan el estándar, no obstante la mayoría tolera este error y oculta deliberadamente las propiedades extras.

Para comprobar los errores del código recomiendo usar jslint.com.

Estructuras en tiempo de compilación

Muchos intérpretes de javascript precompilan el código para mejorar su eficiencia. No obstante, y dada la enorme flexibilidad de javascript, podemos declarar clases mediante prototipado en tiempo de ejecución, en cuyo caso la mejora del rendimiento será mucho menor.

// Declarada en tiempo de compilación
var objeto = {
foo : function( o ){ return o+1; },
bar : function( o ){ return 0; }
};

// Declarada en tiempo de ejecución
var objeto = ( function(){
var r = {};
r.foo = function( o ){ return o + 1; };
r.bar = function( o ){ return 0; };
return r;
}() );
Evitar ejecuciones repetitivas en los bucles

Esto es algo muy común a todos los lenguajes de programación, el evitar llamadas extras innecesarias. Recordemos que el código de dentro de un bucle se ejecutará en todas las iteraciones, de modo que si podemos reducir llamadas extras desde su interior aumentaremos el rendimiento notablemente.

function foo(){return 5;}
// Estos bucles ejecutarán una función en cada iteración.
var i = 0;
while( i < foo()){
i++;
}
for( var j = 0; j < foo(); j++ ){
i++;
}

// Cuando en realidad podrían reducir su ejecución a una única vez
var vfoo = foo(), i = 0;
while( i < vfoo ){
i++;
}
for( var f = 0; j < vfoo; j++ ){
i++;
}

Esta norma incluye una de las penalizaciones de rendimiento más comunes.

var a=[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], b=0;

// Este bucle obtiene, en cada iteración, al atributo length del Array
for( var i = 0; i < a.length; i++ ){
b += a[ i ];
}

// Cuando debería acceder a él una única vez
for( var i = 0, l = a.length; i < l; i++ ){
b += a[ i ];
}

Tened en cuenta que en este último caso, al estar tanto el Array como el bucle en el mismo ámbito de variables, la mejora no es perceptible, pero cuando el Array se encuentra en un ámbito más global, o en un objeto, la mejora es sustancial.

Evita los dinosaurios

Hay miles de frameworks pululando por la red, muchos de ellos demasiado grandes y pesados. Si bien es cierto que es un absurdo el reinventar la rueda con cada nuevo proyecto, también lo es el cargar un framework enorme para sólo utilizar determinada funcionalidad.

Siempre es preferible reutilizar porciones de código conforme se vayan necesitando o, si finalmente optamos por un framework, cerciorarse de que es modular, y evitar ciertas características extremadamente ineficientes que muchos incluyen.

Espero no haberme olvidado de demasiadas cosas, aunque probablemente mantenga el texto actualizado.

0 comentarios:

Publicar un comentario