La función requestAnimationFrame()
es una herramienta muy útil en JavaScript que permite a los desarrolladores web ejecutar animaciones de manera eficiente. Esta función proporciona una forma optimizada de realizar animaciones en el navegador, aprovechando mejor los recursos del sistema y mejorando la experiencia del usuario. A continuación, veremos en detalle qué es, cómo funciona y cómo utilizarla correctamente.
requestAnimationFrame()
?
requestAnimationFrame()
es un método que pertenece al objeto window
en JavaScript y se utiliza para programar la actualización de la pantalla antes de la próxima repintada del navegador. Al usar requestAnimationFrame()
, le indicamos al navegador que queremos realizar una animación y le pedimos que ejecute una función específica para actualizar la animación antes del próximo *repaint*.
requestAnimationFrame()
1. Sincronización con el repintado del navegador: Se ejecuta justo antes de que el navegador vuelva a dibujar la pantalla, lo que asegura una animación más fluida.
2. Optimización del rendimiento: A diferencia de los métodos setTimeout()
o setInterval()
, requestAnimationFrame()
permite al navegador decidir la frecuencia de ejecución, adaptándose a la capacidad del dispositivo.
3. Ahorro de recursos: Cuando la pestaña está en segundo plano o el navegador no está visible, requestAnimationFrame()
pausa la animación, lo que reduce el consumo de recursos y batería.
requestAnimationFrame()
let requestID = window.requestAnimationFrame(callback);
callback
El parámetro callback
es una función que se ejecutará antes de que el navegador vuelva a repintar la pantalla. Esta función recibe un argumento que representa el tiempo actual en milisegundos (similar a performance.now()
), el cual es útil para medir el rendimiento y ajustar la animación.
requestAnimationFrame()
devuelve un identificador único (requestID
), que se puede utilizar posteriormente para cancelar la animación usando cancelAnimationFrame()
.
requestAnimationFrame()
Veamos un ejemplo sencillo para entender cómo funciona. Supongamos que queremos mover un cuadro a través de la pantalla de izquierda a derecha.
const box = document.getElementById('box');
let position = 0;
function moveBox(timestamp) {
position += 2; // Incrementa la posición en cada fotograma
box.style.transform = `translateX(${position}px)`; // Mueve el cuadro
if (position < 300) { // Si la posición es menor a 300px, continúa la animación
requestAnimationFrame(moveBox);
}
}
requestAnimationFrame(moveBox); // Inicia la animación
1. Elemento objetivo: Se selecciona un elemento con el ID box
y se define una variable position
para rastrear la posición del cuadro.
2. Función moveBox()
: Esta función se pasa como *callback* a requestAnimationFrame()
. En cada llamada, se incrementa la posición en 2 píxeles y se actualiza la posición de box
usando transform
.
3. Condición de parada: La animación se detiene cuando la posición es mayor o igual a 300 píxeles.
A continuación, compararemos requestAnimationFrame()
con otros métodos de animación en JavaScript como setTimeout()
y setInterval()
:
+---------------------------+---------------------------+---------------------------+
| Método | Frecuencia de Ejecución| Rendimiento |
+---------------------------+---------------------------+---------------------------+
| requestAnimationFrame() | Sincronizada con el render | Alta eficiencia, pausa en |
| | del navegador (~60 FPS) | segundo plano. |
+---------------------------+---------------------------+---------------------------+
| setTimeout(callback, 16) | Cada 16 ms (~60 FPS) | No se adapta a cambios de |
| | | rendimiento del dispositivo|
+---------------------------+---------------------------+---------------------------+
| setInterval(callback, 16) | Cada 16 ms (~60 FPS) | Continuará ejecutándose |
| | | incluso en segundo plano. |
+---------------------------+---------------------------+---------------------------+
Como se puede ver en la tabla anterior, requestAnimationFrame()
es superior a los métodos tradicionales en cuanto a eficiencia y sincronización con el navegador. Esto se debe a que se ajusta automáticamente a la frecuencia de actualización del monitor y puede pausar la ejecución cuando la pestaña no está visible.
cancelAnimationFrame()
Es posible que en algunas ocasiones necesitemos detener una animación en curso. Para esto, utilizamos cancelAnimationFrame()
. Este método toma como argumento el identificador de la animación (el valor retornado por requestAnimationFrame()
).
let requestID;
let box = document.getElementById('box');
let position = 0;
function moveBox(timestamp) {
position += 2;
box.style.transform = `translateX(${position}px)`;
if (position < 300) {
requestID = requestAnimationFrame(moveBox);
} else {
cancelAnimationFrame(requestID); // Cancela la animación
}
}
requestID = requestAnimationFrame(moveBox);
En este caso, usamos cancelAnimationFrame(requestID)
cuando la posición alcanza 300 píxeles, evitando así que la animación continúe indefinidamente.
requestAnimationFrame()
Además de las animaciones básicas, requestAnimationFrame()
es ideal para:
1. Juegos en 2D y 3D: Sincroniza los fotogramas del juego con el monitor del usuario.
2. Animaciones complejas: Como transiciones de múltiples elementos o cambios de propiedades CSS.
3. Gráficos interactivos: Como gráficos de datos que requieren actualizaciones constantes basadas en la interacción del usuario.
A continuación, implementaremos una animación de rebote de un círculo usando requestAnimationFrame()
:
const ball = document.getElementById('ball');
let x = 0;
let y = 0;
let dx = 2; // Velocidad horizontal
let dy = 2; // Velocidad vertical
const container = document.getElementById('container');
function bounceBall() {
const containerWidth = container.clientWidth;
const containerHeight = container.clientHeight;
x += dx;
y += dy;
// Verifica colisión con los bordes y cambia la dirección
if (x + ball.offsetWidth >= containerWidth || x <= 0) {
dx = -dx;
}
if (y + ball.offsetHeight >= containerHeight || y <= 0) {
dy = -dy;
}
ball.style.transform = `translate(${x}px, ${y}px)`;
requestAnimationFrame(bounceBall);
}
requestAnimationFrame(bounceBall);
En este ejemplo, se mueve un círculo (ball
) dentro de un contenedor (container
). Cada vez que el círculo alcanza los bordes del contenedor, cambia su dirección, creando una animación de rebote fluida y eficiente.
requestAnimationFrame()
es la opción preferida para realizar animaciones en JavaScript gracias a su eficiencia y sincronización con el navegador. Al utilizar este método en lugar de los tradicionales setTimeout()
o setInterval()
, garantizamos que nuestras animaciones sean más fluidas y consuman menos recursos, lo que se traduce en una mejor experiencia para el usuario.
Si deseas llevar tus animaciones al siguiente nivel, te animo a explorar aún más sus capacidades y combinarlas con otras tecnologías como Canvas
y WebGL
.
Jorge García
Fullstack developer