← Назад к вопросам
Можно ли сделать анимацию, используя только промисы?
1.0 Junior🔥 221 комментариев
#JavaScript Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Анимация с использованием Promise
Да, можно создавать анимации, используя только промисы, но это не лучший подход. Давайте разберём, как это работает, какие есть альтернативы и почему они лучше.
Можно ли: Пример с setTimeout + Promise
// Функция для анимации элемента
function animateElement(element, duration = 1000) {
return new Promise((resolve) => {
const startTime = Date.now();
const startOpacity = parseFloat(
window.getComputedStyle(element).opacity
);
function animate() {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
element.style.opacity = startOpacity + (1 - startOpacity) * progress;
if (progress < 1) {
setTimeout(animate, 16); // ~60 FPS
} else {
resolve();
}
}
animate();
});
}
// Использование
const box = document.getElementById('box');
await animateElement(box, 1000);
console.log('Анимация завершена!');
Цепочка анимаций через Promise.then()
const element = document.getElementById('box');
// Анимация 1: Фейд ин
function fadeIn(el, duration = 500) {
return new Promise((resolve) => {
el.style.transition = `opacity ${duration}ms`;
el.style.opacity = 1;
setTimeout(resolve, duration);
});
}
// Анимация 2: Движение вправо
function slideRight(el, distance = 100, duration = 500) {
return new Promise((resolve) => {
el.style.transition = `transform ${duration}ms`;
el.style.transform = `translateX(${distance}px)`;
setTimeout(resolve, duration);
});
}
// Анимация 3: Фейд аут
function fadeOut(el, duration = 500) {
return new Promise((resolve) => {
el.style.transition = `opacity ${duration}ms`;
el.style.opacity = 0;
setTimeout(resolve, duration);
});
}
// Последовательное выполнение
fadeIn(element, 500)
.then(() => slideRight(element, 100, 500))
.then(() => fadeOut(element, 500))
.then(() => {
console.log('Все анимации завершены!');
element.style.display = 'none';
})
.catch(err => console.error('Ошибка:', err));
Или с async/await (более читаемо)
async function runSequentialAnimations() {
const box = document.getElementById('box');
try {
await fadeIn(box, 500);
await slideRight(box, 100, 500);
await fadeOut(box, 500);
console.log('Готово!');
} catch (error) {
console.error('Ошибка анимации:', error);
}
}
runSequentialAnimations();
Почему это НЕ лучший способ
1. Проблема с производительностью
// Плохо: requestAnimationFrame не используется
function slowAnimate(el, duration) {
return new Promise((resolve) => {
const start = Date.now();
const interval = setInterval(() => {
const elapsed = Date.now() - start;
const progress = elapsed / duration;
el.style.left = (progress * 100) + 'px';
if (progress >= 1) {
clearInterval(interval);
resolve();
}
}, 16); // Может быть пропущено браузером
});
}
2. Отсутствие оптимизации браузера
RequestAnimationFrame синхронизируется с fps браузера и пропускает кадры, если вкладка невидима.
3. Сложность управления
Остановить, пауза, перезагрузка — сложнее реализовать с Promise.
Лучший способ: requestAnimationFrame + Promise
function animateWithRAF(element, keyframes, duration) {
return new Promise((resolve) => {
const startTime = performance.now();
function frame(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// Применяем keyframes
const currentFrame = keyframes(progress);
Object.assign(element.style, currentFrame);
if (progress < 1) {
requestAnimationFrame(frame);
} else {
resolve();
}
}
requestAnimationFrame(frame);
});
}
// Использование
await animateWithRAF(box, (progress) => ({
opacity: progress,
transform: `translateX(${progress * 100}px)`
}), 1000);
console.log('Готово!');
Лучший способ: CSS Transitions + Promise
function animateWithCSS(element, className, duration) {
return new Promise((resolve) => {
const handleTransitionEnd = () => {
element.removeEventListener('transitionend', handleTransitionEnd);
resolve();
};
element.addEventListener('transitionend', handleTransitionEnd, { once: true });
element.classList.add(className);
});
}
// CSS
// .fade-in {
// transition: opacity 0.5s ease;
// opacity: 1;
// }
// Использование
await animateWithCSS(box, 'fade-in', 500);
console.log('Анимация завершена!');
Сравнение подходов
| Подход | Производ-ность | Простота | Управление | Использование |
|---|---|---|---|---|
| Promise + setTimeout | Средняя | Средняя | Сложно | Не рекомендуется |
| Promise + requestAnimationFrame | Хорошая | Средняя | Средне | Хорошо |
| CSS Transitions + Promise | Отличная | Простая | Средне | Рекомендуется |
| Framer Motion / Anime.js | Отличная | Простая | Легко | Лучше всего |
Вывод
Да, можно сделать анимацию с Promise, но это не оптимально. Используйте:
- CSS Transitions/Animations — для простых анимаций
- requestAnimationFrame — для сложных анимаций на JavaScript
- Библиотеки (Framer Motion, Anime.js) — для комплексных эффектов
- Promise — только для управления последовательностью, не для самой анимации
Combining Promise с правильными методами анимации (RAF или CSS) даёт лучший результат.