JavaScript a menudo activa cambios visuales. Algunas veces, lo hace directamente mediante manipulaciones de estilo y, otras veces, mediante cálculos que generan cambios visuales, como la búsqueda o clasificación de datos. El JavaScript sincronizado incorrectamente o de larga duración es una causa común de los problemas de rendimiento. Debes intentar minimizar su impacto siempre que sea posible.
JavaScript a menudo activa cambios visuales. A veces eso directamente mediante manipulaciones de estilo y, a veces, cálculos que generan cambios visuales, como ordenar datos o buscarlos. Sincronizada incorrectamente o JavaScript de larga ejecución es una causa común de los problemas de rendimiento. Debes intentar minimizar su impacto siempre que sea posible.
La generación de perfiles de rendimiento de JavaScript puede ser una especie de arte, porque el código JavaScript que escribes nada como el código que se ejecuta en realidad. Los navegadores modernos usan compiladores JIT de optimizaciones y trucos para probar y brindarte la ejecución más rápida posible, cambia sustancialmente la dinámica del código.
Sin embargo, hay algunas acciones que puedes realizar para que tus apps se ejecuten JavaScript.
Resumen
- Evita usar setTimeout o setInterval para realizar actualizaciones visuales. usa siempre requestAnimationFrame en su lugar.
- Desplaza JavaScript de larga duración fuera del subproceso principal y hacia los Web Workers.
- Usa microtareas para realizar cambios en el DOM en varios marcos.
- Utiliza la línea de tiempo de Herramientas para desarrolladores de Chrome y el generador de perfiles de JavaScript para evaluar el impacto de JavaScript.
Usa requestAnimationFrame
para realizar cambios visuales
Cuando se producen cambios visuales en la pantalla, debes trabajar en el momento adecuado
navegador, que se encuentra al comienzo del marco. La única forma de garantizar que tu código JavaScript
que se ejecutará 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 las muestras 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 momento del fotograma, posiblemente en
al final, lo que a menudo puede hacer que perdamos un fotograma y generar bloqueos.
De hecho, jQuery solía usar setTimeout
para su comportamiento de animate
. Fue cambiado para usar
requestAnimationFrame
en la versión 3.
Si usas una versión antigua de jQuery, puedes
Aplicar parches para usar requestAnimationFrame
lo que se recomienda enfáticamente.
Reduce la complejidad o usa Web Workers
JavaScript se ejecuta en el subproceso principal del navegador, junto con los cálculos de estilo, el diseño y, en muchos casos, pintura. Si tu JavaScript se ejecuta por mucho tiempo, bloqueará estas otras tareas, lo que podría hacer que se pierdan fotogramas.
Debes ser estratégico respecto de cuándo se ejecuta JavaScript y durante cuánto tiempo. Por ejemplo, si te encuentras en una animaciones como el desplazamiento. Lo ideal sería que mantengas el JavaScript en algún elemento región de 3-4 ms. Si supera ese tiempo, corres el riesgo de tardar mucho tiempo. Si estás inactivo puedes permitirte relajarte más respecto del tiempo que te toma.
En muchos casos, se puede pasar el trabajo computacional puro Trabajadores web, si, por ejemplo, no requiere acceso al DOM. Manipulación o recorrido de datos, como ordenar o buscar, suelen ser buenos candidatos 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 ajustarse a este modelo: los Web Workers no tienen acceso al DOM. Si tu trabajo debe estar en el subproceso principal, considera un enfoque de lotes, en el que segmentes la tarea más grande en microtareas (cada una no tarda más de unos 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 de que se está procesando una tarea, ya sea mediante un indicador de progreso o de actividad. Cualquiera sea el caso, este enfoque mantendrá libre el subproceso principal de tu app, lo que la ayudará a responder ante interacciones del usuario.
Conoce el “impuesto al fotograma” de JavaScript
Cuando evalúas un framework, una biblioteca o tu propio código, es importante evaluar cuánto cuesta ejecutar el código JavaScript fotograma por fotograma. Este es especialmente importante cuando se hacen trabajos de animación críticos para el rendimiento, como ni la transición ni el desplazamiento.
El panel Performance de las Herramientas para desarrolladores de Chrome es la mejor manera de medir tu Costo de JavaScript. Por lo general, obtienes registros de bajo nivel como este:
La sección Main proporciona un gráfico tipo llama de las llamadas de JavaScript para que podemos analizar exactamente qué funciones se llamaron y cuánto tiempo llevó cada una.
Con esta información, puede evaluar el impacto en el rendimiento de JavaScript en tu aplicación, y comenzarás a detectar y corregir los hotspots en los que funciones están tardando demasiado en ejecutarse. Como mencionamos antes, debes buscar quitar el código JavaScript de larga duración o, si 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 entorno de ejecución para aprender a usarlo el panel Rendimiento.
Evita la microoptimización de tu JavaScript
Puede ser genial saber que el navegador puede ejecutar una versión de algo 100 veces más rápido que
por ejemplo, solicitar el offsetTop
de un elemento es más rápido que procesar
getBoundingClientRect()
. Sin embargo, casi siempre es cierto que solo llamarás a funciones como
una pequeña cantidad de veces por fotograma, por lo que es un desperdicio de esfuerzo
Rendimiento de JavaScript Por lo general, solo ahorrarás fracciones de milisegundos.
Si estás creando un juego o una aplicación costosa desde el punto de vista informático, es probable que seas una excepción. ya que generalmente harás mucho trabajo en un solo fotograma, en ese caso, todo sirve.
En resumen, debe ser muy cauteloso con las microoptimizaciones porque, por lo general, no se asignan al tipo de aplicación que estás creando.