requestAnimationFrame vs setTimeout: Cuándo Usar Cada Uno
Comprende las diferencias entre requestAnimationFrame y setTimeout, y aprende cuándo usar cada uno para animaciones fluidas y código eficiente.
TL;DR - Resumen rápido
- requestAnimationFrame está sincronizado con el refresh rate del navegador (típicamente 60 FPS)
- setTimeout tiene un delay mínimo de 4ms y no está sincronizado con el refresh rate
- requestAnimationFrame se pausa automáticamente cuando la pestaña está inactiva, ahorrando batería
- Usa requestAnimationFrame para animaciones y actualizaciones visuales
- Usa setTimeout para tareas que necesitan ejecutarse en intervalos específicos independientes del rendering
Introducción
Tanto requestAnimationFrame como setTimeout son APIs de JavaScript para ejecutar código de manera asíncrona, pero tienen propósitos muy diferentes y comportamientos distintos. Elegir la API correcta para cada caso de uso es fundamental para crear animaciones fluidas, ahorrar recursos del sistema y escribir código eficiente.
requestAnimationFrame está diseñado específicamente para animaciones y actualizaciones visuales, sincronizándose con el ciclo de renderizado del navegador. setTimeout es una API más general para ejecutar código después de un delay específico. Comprender sus diferencias te ayudará a tomar decisiones informadas sobre cuál usar en cada situación.
¿Qué es requestAnimationFrame?
requestAnimationFrame es una API del navegador diseñada específicamente para animaciones y actualizaciones visuales. Solicita al navegador que ejecute una función de callback antes del próximo repaint (repintado) de la página. El navegador optimiza estas llamadas para que se ejecuten a la tasa de refresco del display (típicamente 60 veces por segundo en monitores estándar, o 120/144 Hz en monitores de alta frecuencia).
requestAnimationFrame devuelve un ID que puedes usar para cancelar la animación con cancelAnimationFrame. Esto es importante para limpiar animaciones cuando ya no se necesitan, evitando memory leaks y consumo innecesario de CPU.
Este ejemplo muestra el uso básico de requestAnimationFrame. La función animate se llama recursivamente, actualizando la posición de un elemento en cada frame. La animación se detiene cuando la condición se cumple, usando cancelAnimationFrame para limpiar la animación.
Sincronización Perfecta con el Refresh Rate
requestAnimationFrame se ejecuta exactamente antes de que el navegador repinte la página, garantizando que las actualizaciones visuales se muestren en el momento óptimo. Esto elimina tearing visual y produce animaciones suaves y consistentes.
¿Qué es setTimeout?
setTimeout es una API de JavaScript que ejecuta una función después de un delay específico en milisegundos. A diferencia de requestAnimationFrame, setTimeout no está sincronizado con el ciclo de renderizado del navegador y puede ejecutarse en cualquier momento después del delay especificado.
setTimeout tiene un delay mínimo de 4ms en navegadores modernos cuando se encadena múltiples llamadas. Esto significa que setTimeout(fn, 0) no ejecuta la función inmediatamente, sino que la agrega a la task queue para ejecutarse después de al menos 4ms.
Este ejemplo muestra el uso básico de setTimeout. La función executeRepeatedly se llama a sí misma con setTimeout, creando un bucle que se ejecuta cada 100ms. Este patrón es útil para tareas que necesitan ejecutarse en intervalos específicos pero no están relacionadas con animaciones visuales.
setTimeout No Es Preciso
setTimeout no garantiza ejecución exacta en el tiempo especificado. El delay es el tiempo mínimo antes de que la función se agregue a la task queue, pero la ejecución real depende de cuándo el event loop esté libre. Para tareas que requieren precisión temporal, considera usar Web Workers o Performance API.
Diferencias Clave
Las diferencias entre requestAnimationFrame y setTimeout son significativas y afectan directamente el rendimiento y el comportamiento de tu código. Comprender estas diferencias te ayudará a elegir la API correcta para cada caso de uso.
Sincronización con el Refresh Rate
requestAnimationFrame está sincronizado con el refresh rate del navegador, ejecutándose típicamente a 60 FPS (16.67ms por frame) en monitores estándar. Esto garantiza que las animaciones se vean suaves y consistentes. setTimeout, por otro lado, no está sincronizado y puede ejecutarse en cualquier momento, lo que puede causar animaciones entrecortadas.
Este ejemplo compara la sincronización de requestAnimationFrame y setTimeout. requestAnimationFrame se ejecuta consistentemente a ~16.67ms (60 FPS), mientras que setTimeout tiene variaciones en el tiempo de ejecución y puede ejecutarse más rápido o más lento que el refresh rate.
Comportamiento en Pestañas Inactivas
requestAnimationFrame se pausa automáticamente cuando la pestaña está inactiva o minimizada, ahorrando batería y recursos del sistema. setTimeout continúa ejecutándose incluso cuando la pestaña está inactiva, lo que puede consumir batería innecesariamente si la animación o tarea no es necesaria en segundo plano.
Este ejemplo muestra el comportamiento en pestañas inactivas. requestAnimationFrame se pausa cuando cambias a otra pestaña, mientras que setTimeout continúa ejecutándose. Esto es importante para aplicaciones que deben ser eficientes en el uso de batería.
Precisión y Consistencia
requestAnimationFrame ofrece mejor precisión y consistencia para animaciones porque está sincronizado con el ciclo de renderizado del navegador. setTimeout tiene variaciones en el tiempo de ejecución debido al event loop y otros factores del sistema, lo que puede causar animaciones irregulares.
requestAnimationFrame se ejecuta antes de cada repaint del navegador, mientras que setTimeout se ejecuta cuando el event loop está libre, sin sincronización con el refresh rate. Esto hace que requestAnimationFrame tenga menos jitter (variación) y sea más eficiente para animaciones visuales.
Cuándo Usar requestAnimationFrame
requestAnimationFrame es ideal para cualquier tarea relacionada con animaciones o actualizaciones visuales. Su sincronización con el refresh rate del navegador y su comportamiento de pausa en pestañas inactivas lo hacen perfecto para crear animaciones fluidas y eficientes.
- Animaciones de elementos del DOM (posicionamiento, rotación, escala)
- Animaciones de canvas y WebGL
- Actualizaciones de scroll suave
- Animaciones de transiciones de UI
- Cualquier actualización visual que deba verse fluida
- Animaciones que deben pausarse cuando la pestaña está inactiva
requestAnimationFrame para Todo lo Visual
Como regla general, usa requestAnimationFrame para cualquier cosa que afecte lo que el usuario ve en la pantalla. Esto incluye animaciones, transiciones, scroll suave y cualquier actualización visual. Tu código será más eficiente y tus animaciones serán más fluidas.
Cuándo Usar setTimeout
setTimeout es más adecuado para tareas que necesitan ejecutarse en intervalos específicos independientes del rendering del navegador. Esto incluye tareas de fondo, polling, debounce/throttle y operaciones que no están relacionadas con animaciones visuales.
- Debounce y throttle de eventos (scroll, resize, input)
- Polling de APIs o datos
- Tareas de fondo que deben ejecutarse en intervalos específicos
- Retrasos intencionales (mostrar un mensaje después de X segundos)
- Reintentos de operaciones fallidas con backoff exponencial
- Tareas que deben ejecutarse incluso cuando la pestaña está inactiva
setTimeout para Tareas No Visuales
Usa setTimeout para tareas que no afectan directamente lo que el usuario ve. Esto incluye debounce/throttle, polling, reintentos y cualquier operación que necesite ejecutarse en un intervalo específico pero no esté relacionada con animaciones visuales.
Ejemplos Prácticos
Veamos ejemplos prácticos de cuándo usar cada API. Estos ejemplos muestran patrones comunes que encontrarás en aplicaciones web reales y cómo implementarlos correctamente con la API adecuada.
Animación con requestAnimationFrame
Este ejemplo muestra cómo crear una animación suave usando requestAnimationFrame. La animación mueve un elemento horizontalmente y se detiene cuando alcanza una posición específica.
Este ejemplo implementa una animación suave usando requestAnimationFrame. La función animate actualiza la posición del elemento en cada frame y se detiene cuando alcanza la posición objetivo. El uso de requestAnimationFrame garantiza que la animación se vea fluida a 60 FPS.
Siempre Cancela Animaciones
Siempre guarda el ID retornado por requestAnimationFrame y cancela la animación con cancelAnimationFrame cuando ya no la necesites. Esto evita memory leaks y consumo innecesario de CPU. En frameworks como React, usa el cleanup function de useEffect para cancelar animaciones.
Debounce con setTimeout
Este ejemplo muestra cómo implementar debounce usando setTimeout. Debounce es una técnica para limitar la frecuencia de ejecución de una función, ejecutándola solo después de que haya pasado un tiempo específico desde la última invocación.
Este ejemplo implementa debounce usando setTimeout. La función debounce devuelve una nueva función que espera el tiempo especificado antes de ejecutar la función original. Si se llama nuevamente antes de que el tiempo expire, se reinicia el timer. Esto es útil para eventos como scroll, resize e input.
Resumen: requestAnimationFrame vs setTimeout
Conceptos principales:
- •requestAnimationFrame está sincronizado con el refresh rate del navegador (~60 FPS)
- •setTimeout no está sincronizado con el refresh rate y tiene un delay mínimo de 4ms
- •requestAnimationFrame se pausa automáticamente cuando la pestaña está inactiva
- •setTimeout continúa ejecutándose incluso cuando la pestaña está inactiva
- •requestAnimationFrame ofrece mejor precisión y consistencia para animaciones
- •setTimeout tiene más variación en el tiempo de ejecución debido al event loop
Mejores prácticas:
- •Usa requestAnimationFrame para animaciones y actualizaciones visuales
- •Usa setTimeout para debounce/throttle, polling y tareas de fondo
- •Siempre cancela requestAnimationFrame con cancelAnimationFrame cuando ya no se necesite
- •Usa setTimeout para tareas que deben ejecutarse en intervalos específicos
- •Evita usar setTimeout para animaciones visuales, usa requestAnimationFrame en su lugar
- •Considera el impacto en batería al elegir entre rAF y setTimeout