Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Для чего используются промисы?
Promise (Промис) — это объект JavaScript, который представляет будущий результат асинхронной операции. Это один из самых важных концептов современного JavaScript.
Что такое Promise?
// Promise — это объект с тремя состояниями:
// 1. Pending (ожидание) — операция не завершена
// 2. Resolved (выполнено) — операция успешно завершилась
// 3. Rejected (отклонено) — произошла ошибка
const myPromise = new Promise((resolve, reject) => {
// resolve() — переводит в состояние Resolved
// reject() — переводит в состояние Rejected
setTimeout(() => {
resolve('Успешно!');
}, 1000);
});
// Используем промис
myPromise
.then(result => console.log(result)) // Успешно!
.catch(error => console.error(error)); // Обработка ошибки
Для чего нужны промисы?
1. Асинхронные операции
Промисы используются для операций, которые занимают время:
// Сетевой запрос
fetch('https://api.example.com/users/123')
.then(response => response.json())
.then(user => console.log(user))
.catch(error => console.error('Ошибка:', error));
// Работа с файлами
fs.readFile('data.json', (err, data) => {
// Callback hell! Вместо этого используй промисы
});
// Timeout
new Promise(resolve => {
setTimeout(() => resolve('готово'), 1000);
}).then(result => console.log(result));
2. Обработка ошибок
Промисы предоставляют удобный способ обработки ошибок:
// Без промисов: callback hell
getUser(id, (err, user) => {
if (err) {
console.error('Ошибка при получении пользователя');
} else {
getPost(user.id, (err, post) => {
if (err) {
console.error('Ошибка при получении поста');
} else {
console.log(post);
}
});
}
});
// С промисами: намного чище
getUser(id)
.then(user => getPost(user.id))
.then(post => console.log(post))
.catch(error => console.error('Ошибка:', error)); // Одна обработка для всех ошибок
3. Цепочки асинхронных операций
Промисы позволяют выполнять операции последовательно:
// Сценарий: получить пользователя -> его посты -> комментарии первого поста
getUser(123)
.then(user => {
console.log('Пользователь:', user.name);
return getPosts(user.id); // Возвращаем новый промис
})
.then(posts => {
console.log('Посты:', posts.length);
return getComments(posts[0].id); // Следующий промис
})
.then(comments => {
console.log('Комментарии:', comments);
})
.catch(error => {
console.error('Произошла ошибка:', error);
});
Основные методы Promise
then() — обработка успеха
const promise = Promise.resolve('успех');
promise.then(result => {
console.log(result); // успех
});
// then() возвращает новый промис
promise
.then(result => result.toUpperCase())
.then(result => console.log(result)); // УСПЕХ
catch() — обработка ошибки
const failedPromise = Promise.reject(new Error('Что-то пошло не так'));
failedPromise.catch(error => {
console.error(error.message); // Что-то пошло не так
});
// catch() также возвращает промис
failedPromise
.catch(error => {
console.error('Обработали ошибку:', error);
return 'значение по умолчанию'; // Восстанавливаемся
})
.then(value => console.log(value));
finally() — выполнить в конце
fetch('/api/users')
.then(res => res.json())
.then(data => console.log(data))
.catch(error => console.error(error))
.finally(() => {
// Выполнится в любом случае — успех или ошибка
console.log('Запрос завершён');
hideLoadingSpinner();
});
Promise.all() — ждём все промисы
// Запустить несколько асинхронных операций параллельно
const userPromise = fetch('/api/users/123').then(r => r.json());
const postsPromise = fetch('/api/posts/123').then(r => r.json());
const commentsPromise = fetch('/api/comments/123').then(r => r.json());
// Promise.all ждёт, пока ВСЕ промисы выполнятся
Promise.all([
userPromise,
postsPromise,
commentsPromise,
])
.then(([user, posts, comments]) => {
console.log('Данные готовы:', { user, posts, comments });
})
.catch(error => {
console.error('Одна из операций не удалась:', error);
});
// Практический пример: загрузить несколько изображений
Promise.all([
loadImage('img1.jpg'),
loadImage('img2.jpg'),
loadImage('img3.jpg'),
])
.then(images => {
console.log('Все изображения загружены');
renderGallery(images);
})
.catch(() => {
console.error('Не удалось загрузить одно из изображений');
});
Promise.race() — первый завершённый промис
// Выполнить несколько операций, использовать первую успешную
Promise.race([
fetch('api1.example.com/data'),
fetch('api2.example.com/data'),
fetch('api3.example.com/data'),
])
.then(response => response.json())
.then(data => console.log('Первый ответ:', data))
.catch(error => console.error('Все API недоступны'));
// Практический пример: timeout
Promise.race([
fetch('/api/users'),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), 5000)
),
])
.then(res => res.json())
.catch(error => console.error('Ошибка или timeout:', error));
Async/Await — синтаксический сахар над Promise
// Промисы можно использовать с async/await (более современный подход)
// С промисами (старый способ)
function getUserData(id) {
return fetch(`/api/users/${id}`)
.then(res => res.json())
.then(user => {
return fetch(`/api/posts/${user.id}`)
.then(res => res.json())
.then(posts => ({ user, posts }));
});
}
// С async/await (новый способ)
async function getUserData(id) {
const userRes = await fetch(`/api/users/${id}`);
const user = await userRes.json();
const postsRes = await fetch(`/api/posts/${user.id}`);
const posts = await postsRes.json();
return { user, posts };
}
// Использование
getUserData(123)
.then(data => console.log(data))
.catch(error => console.error(error));
Практические примеры в React
Загрузка данных
import { useEffect, useState } from 'react';
function UserProfile({ id }: { id: string }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// Используем промис для загрузки данных
fetch(`/api/users/${id}`)
.then(res => res.json())
.then(data => {
setUser(data);
setLoading(false);
})
.catch(err => {
setError(err.message);
setLoading(false);
});
}, [id]);
if (loading) return <div>Загрузка...</div>;
if (error) return <div>Ошибка: {error}</div>;
return <div>{user.name}</div>;
}
Отправка формы
function ContactForm() {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
// Промис для отправки данных
fetch('/api/contact', {
method: 'POST',
body: formData,
})
.then(res => {
if (!res.ok) throw new Error('Ошибка сервера');
return res.json();
})
.then(data => {
alert('Спасибо за сообщение!');
})
.catch(error => {
alert('Ошибка: ' + error.message);
});
};
return (
<form onSubmit={handleSubmit}>
<input name="email" type="email" required />
<button type="submit">Отправить</button>
</form>
);
}
Параллельная загрузка данных
function Dashboard() {
const [data, setData] = useState(null);
useEffect(() => {
// Загрузить несколько источников данных одновременно
Promise.all([
fetch('/api/users').then(r => r.json()),
fetch('/api/analytics').then(r => r.json()),
fetch('/api/reports').then(r => r.json()),
])
.then(([users, analytics, reports]) => {
setData({ users, analytics, reports });
})
.catch(error => {
console.error('Ошибка загрузки данных:', error);
});
}, []);
if (!data) return <div>Загрузка...</div>;
return (
<div>
<Users data={data.users} />
<Analytics data={data.analytics} />
<Reports data={data.reports} />
</div>
);
}
Проблемы и решения
Проблема: Callback Hell
// Плохо: вложенные callbacks
getUser(id, (err, user) => {
if (!err) {
getPosts(user.id, (err, posts) => {
if (!err) {
getComments(posts[0].id, (err, comments) => {
if (!err) {
console.log(comments);
}
});
}
});
}
});
// Хорошо: промисы
getUser(id)
.then(user => getPosts(user.id))
.then(posts => getComments(posts[0].id))
.then(comments => console.log(comments))
.catch(error => console.error(error));
Проблема: утечка памяти
// Плохо: промис может оставить listener висеть
useEffect(() => {
fetch('/api/data').then(res => res.json());
// Если компонент демонтируется, промис выполнится всё равно!
}, []);
// Хорошо: отмена промиса через AbortController
useEffect(() => {
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal })
.then(res => res.json())
.then(data => setData(data))
.catch(error => {
if (error.name !== 'AbortError') {
console.error(error);
}
});
return () => controller.abort(); // Отмена при демонтировании
}, []);
Заключение
Промисы нужны для:
- Асинхронных операций — сетевые запросы, работа с файлами, таймауты
- Обработки ошибок — единый способ обработать ошибки
- Цепочек операций — выполнить операции друг за другом
- Параллельных операций — Promise.all, Promise.race
- Управления потоком выполнения — контролировать порядок выполнения кода
Промисы — это фундамент современного JavaScript. Без понимания промисов невозможно писать современные приложения на React, Node.js и других технологиях.