A menudo, JavaScript activa cambios visuales. A veces, esto se hace directamente a través de manipulaciones de estilo y, a veces, son cálculos que generan cambios visuales, como buscar o ordenar datos. El código JavaScript mal sincronizado o de larga duración es una causa común de problemas de rendimiento. Debes intentar minimizar su impacto siempre que puedas.
A menudo, JavaScript activa cambios visuales. A veces, esto se hace directamente a través de manipulaciones de diseño y, a veces, son cálculos que generan cambios visuales, como buscar o ordenar datos. El código JavaScript con un tiempo de ejecución incorrecto o prolongado es una causa común de problemas de rendimiento. Debes intentar minimizar su impacto siempre que puedas.
La generación de perfiles de rendimiento de JavaScript puede ser un arte, ya que el código JavaScript que escribes no se parece en nada al código que se ejecuta. Los navegadores modernos usan compiladores JIT y todo tipo de optimizaciones y trucos para intentar brindarte la ejecución más rápida posible, lo que cambia de forma sustancial la dinámica del código.
Dicho esto, hay algunas medidas que puedes tomar para ayudar a que tus apps ejecuten JavaScript de forma correcta.
Resumen
- Evita setTimeout o setInterval para las actualizaciones visuales. En su lugar, usa siempre requestAnimationFrame.
- Quita el código JavaScript de larga duración del subproceso principal y muévelo a los trabajadores web.
- Usa microtareas para realizar cambios en el DOM en varios fotogramas.
- Usa el cronograma y el generador de perfiles de JavaScript de las Herramientas para desarrolladores de Chrome para evaluar el impacto de JavaScript.
Usa requestAnimationFrame
para los cambios visuales
Cuando se producen cambios visuales en la pantalla, debes realizar tu trabajo en el momento adecuado para el navegador, que es justo al comienzo del fotograma. La única forma de garantizar que tu código JavaScript se ejecute al comienzo de un fotograma es usar requestAnimationFrame
.
/**
* If run as a requestAnimationFrame callback, this
* will be run at the start of the frame.
*/
function updateScreen(time) {
// Make visual updates here.
}
requestAnimationFrame(updateScreen);
Los frameworks o ejemplos pueden usar setTimeout
o setInterval
para realizar cambios visuales, como animaciones,
pero el problema con esto es que la devolución de llamada se ejecutará en algún punto del fotograma, posiblemente al
final, y eso puede provocar que perdamos un fotograma, lo que genera interrupciones.

De hecho, jQuery solía usar setTimeout
para su comportamiento animate
. Se cambió para usar requestAnimationFrame
en la versión 3.
Si usas una versión anterior de jQuery, puedes corregirla para usar requestAnimationFrame
, lo que se recomienda.
Reduce la complejidad o usa trabajadores web
JavaScript se ejecuta en el subproceso principal del navegador, junto con los cálculos de estilo, el diseño y, en muchos casos, la pintura. Si tu código JavaScript se ejecuta durante mucho tiempo, bloqueará estas otras tareas, lo que podría provocar que se pierdan fotogramas.
Debes ser táctico sobre cuándo se ejecuta JavaScript y durante cuánto tiempo. Por ejemplo, si estás en una animación como el desplazamiento, lo ideal es que intentes mantener tu JavaScript en un valor de entre 3 y 4 ms. Si tardas más, corres el riesgo de ocupar demasiado tiempo. Si estás en un período de inactividad, puedes permitirte relajarte con respecto al tiempo que lleva.
En muchos casos, puedes mover el trabajo computacional puro a los trabajadores en la Web si, por ejemplo, no requiere acceso al DOM. La manipulación o el recorrido de datos, como la ordenación o la búsqueda, suelen ser una buena opción para este modelo, al igual que la carga y la generación de modelos.
var dataSortWorker = new Worker("sort-worker.js");
dataSortWorker.postMesssage(dataToSort);
// The main thread is now free to continue working on other things...
dataSortWorker.addEventListener('message', function(evt) {
var sortedData = evt.data;
// Update data on screen...
});
No todo el trabajo puede adaptarse a este modelo: los trabajadores web no tienen acceso al DOM. Cuando tu trabajo debe estar en el subproceso principal, considera un enfoque por lotes, en el que segmentes la tarea más grande en microtareas, cada una de las cuales no tarde más de unos pocos milisegundos, y se ejecute dentro de los controladores requestAnimationFrame
en cada fotograma.
Este enfoque tiene consecuencias para la UX y la IU, y deberás asegurarte de que el usuario sepa que se está procesando una tarea, ya sea con un indicador de progreso o de actividad. En cualquier caso, este enfoque mantendrá el subproceso principal de tu app libre, lo que la ayudará a seguir siendo receptiva a las interacciones del usuario.
Conoce el "impuesto de fotogramas" de tu JavaScript
Cuando evalúes un framework, una biblioteca o tu propio código, es importante evaluar cuánto cuesta ejecutar el código JavaScript fotograma por fotograma. Esto es muy importante cuando se realiza un trabajo de animación fundamental para el rendimiento, como la transición o el desplazamiento.
El panel Rendimiento de las Herramientas para desarrolladores de Chrome es la mejor manera de medir el costo de tu código JavaScript. Por lo general, obtienes registros de bajo nivel como este:

La sección Main proporciona un gráfico tipo llama de las llamadas a JavaScript para que puedas analizar exactamente a qué funciones se llamó y cuánto tiempo tardó cada una.
Con esta información, puedes evaluar el impacto del rendimiento de JavaScript en tu aplicación y comenzar a encontrar y corregir los puntos calientes en los que las funciones tardan demasiado en ejecutarse. Como se mencionó anteriormente, debes intentar quitar el código JavaScript de larga duración o, si eso no es posible, moverlo a un trabajador web para liberar el subproceso principal y continuar con otras tareas.
Consulta Cómo comenzar a analizar el rendimiento del tiempo de ejecución para aprender a usar el panel Rendimiento.
Evita microoptimizar tu código JavaScript
Puede ser interesante saber que el navegador puede ejecutar una versión de algo 100 veces más rápido que
otro, como que solicitar el offsetTop
de un elemento es más rápido que calcular
getBoundingClientRect()
, pero casi siempre es cierto que solo llamarás a funciones como estas una pequeña cantidad de veces por fotograma, por lo que, por lo general, es un esfuerzo desperdiciado enfocarse en este aspecto del rendimiento de
JavaScript. Por lo general, solo ahorrarás fracciones de milisegundos.
Si estás creando un juego o una aplicación con un procesamiento costoso, es probable que seas una excepción a esta guía, ya que, por lo general, ajustas muchos cálculos en un solo fotograma y, en ese caso, todo ayuda.
En resumen, debes tener mucho cuidado con las microoptimizaciones, ya que, por lo general, no se asignarán al tipo de aplicación que compilas.