Con motivos de celebración por el segundo aniversario de Codize, y siendo que aun es moneda corriente encontrarse errores de optimización en JavaScript hemos decidido presentar esta serie dividida en tres partes. En esta oportunidad una lista de consejos básicos para mejorar el rendimiento JavaScript, formas de optimizar el rendimiento del código JS que todo el mundo puede aplicar y que suele ocurrir cuando uno comienza a desarrollar. A diferencia de otras entregas, vamos a explicar las razones detrás de la optimización, de modo tal que al adquirir el conocimiento cada desarrollador pueda evaluar si emplear dicha optimización o no (copiar código está bien, siempre y cuando se entienda lo que se está haciendo).
Variables con let y const
A los que aprendimos JavaScript hace más de década se nos enseñó que JS no era muy estricto en su tipado. De hecho, es bastante permisivo, se puede escribir un código completo sin usar el punto-y-coma, la sintaxis no debe ser perfecta, las tabulaciones pueden ni existir; y en esa marea de permisos siempre se nos decía que no había constantes ni variables en JS, y que toda variable era declarada con el operador var. Con var se resolvía todo. En lo personal siempre me llamó la atención, si quiero una variable booleana de uso local entonces tendrá reservada la misma memoria que una variable más compleja como puede ser un objeto. En realidad es más complicado que eso, pero lo correcto es entender una cosa, que hoy por hoy var se usa solo en una situación: variables globales del sistema, pero completamente globales. Algo que se declare fuera de un objeto y se pueda acceder desde cualquier lugar. Para todo lo demás se usa let, una versión de var menos "omnipresente" que se limita a su propio entorno, el 99% de las veces es la opción correcta y permite un código más limpio y optimizado para JS. Y en caso de requerir una variable que no cambie nunca (una constante) lo correcto es el operador const.
Resetear un Array
En muchas ocaciones necesitamos "limpiar" un Array para agregarle nuevos elementos. Esto es bastante frecuente. Pero en JS suelo ver que mucha gente resetea los Arrays asi:
arr = []
Si bien es correcto, esta acción volverá a declarar el array, y lo que queremos es resetearlo por lo tanto vamos a estar consumiendo un poco más de recursos. La forma correcta sería cambiando su tamaño a 0, para forzar que se resetee sin volver a declararse:
arr.length = 0
Los bloques for-of y for-in
Por lo dinámico del lenguaje muchas veces nos perdemos nuevos cambios al motor de ES (la base de JavaScript) y desconocemos formas mas eficientes de hacer lo mismo años atrás. Hace ya bastante que los bloques for-of y for-in se han vuelto un estándar, pero se suelen ver bastante poco. Sigue siendo común encontrarse la típica cadena de for en un array:
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
Esto es muy clásico y útil, claro está, pero puede obtenerse un resultado igual con menos código y más legible utilizando for-of:
for (let i of arr) {
console.log(i);
}
Es bastante más claro y útil al momento de debugear. Por su parte for-in se utiliza cuando el orden del objeto no es importante, por lo cual es menos empleado. Respecto a su optimización, aun está en debate cual es el mejor en términos de eficiencia (puede que el for clásico sea levemente mejor). Lo importante es lo que se gana en terminos de optimización de código, debuguear algo con un for-of es sumamente cómodo a comparación.
Eliminación del console.log en producción
Esto es algo que también sucede mucho. Está genial utilizar loguers de todo tipo, pero por más que sea ridículo afectan bastante al rendimiento si estamos imprimiendo información todo el tiempo. Y claro, la solución no es simplemente "eliminarlos" ya que son de gran utilidad mientras se desarrolla. Pero en una web de producción, incluso en una app, son casi irrelevantes. Por lo tanto, si sabemos que no los vamos a necesitar en producción, lo mejor es utilizar alguna herramienta para eliminar logs del código compilado (atención con esto, no eliminen nunca los console.log de desarrollo, siempre al compilar). Esto se puede incluso automatizar con Python u otras herramientas. Una opción rápida puede ser utilizar el VSCode con un simple Regex:
console.log.*$
Animaciones CSS en lugar de JS
Esto es un error heredado de hace años que por suerte se ve cada vez menos. Cuando salió CSS3 todo el mundo empezó a jugar con las animaciones que antes se hacían únicamente con JavaScript. El caso es que debido a la compatibilidad muchos prefirieron seguir con JS y algunos todavía heredan dicho "legacy system". Concretamente, una animación JS lo que hace es actualizar el DOM para generar la simulación de movimiento. Es verdaderamente pesado en términos de consumo de CPU hacer algo así. Por su parte CSS está preparado para realizar la animación de forma nativa, reduciendo el consumo en todo sentido (aunque claro, una animación siempre consume más que algo fijo, pero podemos afirmar que con CSS es algo más "verde"). Y si la preocupación es la compatibilidad, cerca del 97% del mercado de los navegadores soportan keyframe y transition, así que es una opción altamente recomendada.
Evitar jQuery o reducir su uso
Llegamos al final con el problema de jQuery. Pasó de ser amado en la web a un gran problema de recursos. Lamentablemente, con los frameworks modernos que hay dando vuelta hoy día, sumado a todo lo nativo de JS, jQuery aporta muy poco. Sugiero tratar de evitarlo en proyectos nuevos.
En aquellos proyectos donde jQuery sea una dependencia obligatoria (por ejemplo, en Odoo sigue siendo una de sus grandes dependencias) entonces nos queda adaptarnos. Inicialmente hay que tratar de usarlo lo menos posible, ya que muchas de sus opciones son pesadas. Concretamente hay una, la de buscar un elemento con cierto nombre (una clase por ejemplo) dentro de otro elemento, o un child posicional de un elemento en cuestión. Esta operación es recursiva y pesadísima para JavaScript, y es aconsejable utilizar JavaScript puro mediante un getElementById o un index a utilizar jQuery para ubicarlo.