RequestAnimationFrame: примеры (JAVASCRIPT)

Функция requestAnimationFrame для анимации в браузере
Раздел: Анимация, Управление
requestAnimationFrame(callback: function): number (id for cancellation)

Основные сведения о requestAnimationFrame

Функция requestAnimationFrame является частью JavaScript API и предназначена для создания плавной анимации в браузере. Она сообщает браузеру о необходимости выполнить анимацию и запрашивает вызов указанной функции перед следующей перерисовкой страницы.

Основное применение функции — создание анимации, которая синхронизирована с частотой обновления экрана устройства. Это позволяет добиться оптимальной производительности и избежать лишних вычислений, когда страница неактивна или скрыта.

Аргументы функции:

  • callback — единственный обязательный параметр. Это функция, которая будет вызвана перед следующей перерисовкой. Она получает один аргумент — DOMHighResTimeStamp, указывающий время, когда запланирован вызов callback.

Возвращаемое значение — числовой идентификатор запроса, который можно передать в cancelAnimationFrame для отмены вызова.

Примеры базового использования

Простейший пример анимации движения элемента.

let start;
function step(timestamp) {
if (!start) start = timestamp;
const progress = timestamp - start;
element.style.transform = `translateX(${Math.min(progress / 10, 200)}px)`;
if (progress < 2000) {
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);

Пример использования с отменой анимации.

let animationId;
function animate() {
// Логика анимации
animationId = requestAnimationFrame(animate);
}
animationId = requestAnimationFrame(animate);
// Для остановки:
// cancelAnimationFrame(animationId);

Похожие функции в JavaScript

setInterval и setTimeout — традиционные методы для периодического выполнения кода. Они не привязаны к циклу отрисовки браузера, что может вызвать пропуск кадров или излишние вычисления. Предпочтительнее использовать requestAnimationFrame для визуальных анимаций.

Intersection Observer API — позволяет асинхронно отслеживать видимость элементов. Используется для ленивой загрузки или запуска анимации при появлении элемента в viewport. Для анимации движения лучше подходит requestAnimationFrame.

Типичные ошибки

Рекурсивный вызов без условия остановки приводит к бесконечной анимации и нагрузке на процессор.

function animate() {
// Изменение состояния
requestAnimationFrame(animate); // Вызывается всегда
}
animate(); // Нельзя остановить

Игнорирование временной метки вызывает анимацию, зависящую от скорости выполнения, а не от реального времени.

let position = 0;
function animate() {
position += 5; // Скорость зависит от частоты кадров
element.style.left = position + 'px';
requestAnimationFrame(animate);
}

Изменения в последних версиях

Функция requestAnimationFrame была стандартизирована в спецификации HTML5. Современные браузеры поддерживают высокоточную временную метку DOMHighResTimeStamp. В более старых реализациях метка времени могла быть с меньшей точностью.

В последних версиях браузеров функция оптимизирована для работы в фоновых вкладках — частота вызовов снижается для экономии ресурсов. Это поведение определено в спецификации Page Visibility API.

Расширенные примеры использования

Анимация с линейной интерполяцией по времени.

Пример javascript
const duration = 2000; // 2 секунды
const startPosition = 0;
const endPosition = 300;
let startTime;
function animate(timestamp) {
if (!startTime) startTime = timestamp;
const elapsed = timestamp - startTime;
const progress = Math.min(elapsed / duration, 1);
const currentPosition = startPosition + (endPosition - startPosition) * progress;
element.style.transform = `translateX(${currentPosition}px)`;
if (progress < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);

Использование для контроля частоты кадров в игровом цикле.

Пример javascript
let lastTime = 0;
const fps = 30;
const frameInterval = 1000 / fps;
function gameLoop(timestamp) {
if (timestamp - lastTime >= frameInterval) {
// Логика игры
lastTime = timestamp;
}
requestAnimationFrame(gameLoop);
}
gameLoop();

Создание плавного скролла с использованием requestAnimationFrame.

Пример javascript
function smoothScrollTo(targetY, duration = 1000) {
const startY = window.scrollY;
const distance = targetY - startY;
let startTime;
function scrollStep(timestamp) {
if (!startTime) startTime = timestamp;
const elapsed = timestamp - startTime;
const progress = Math.min(elapsed / duration, 1);
const ease = progress < 0.5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress;
window.scrollTo(0, startY + distance * ease);
if (progress < 1) {
requestAnimationFrame(scrollStep);
}
}
requestAnimationFrame(scrollStep);
}

Аналоги в других языках программирования

В Python для создания анимаций в библиотеке PyGame используется основной игровой цикл с контролем FPS.

import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Логика анимации
pygame.display.flip()
clock.tick(60) # Ограничение до 60 кадров в секунду

В C/C++ для графических приложений используются специализированные API (OpenGL, DirectX) и циклы сообщений. Концепция запроса следующего кадра отсутствует, так как управление происходит через системные события.

JS requestAnimationFrame function comments

En
RequestAnimationFrame Schedules a function to be called before the next repaint, ideal for smooth animations.