Что такое Promise в JavaScript?
Что такое Promise
Promise (промис) — это встроенный объект JavaScript, который представляет собой обёртку над значением, которое может быть ещё неизвестно в момент создания промиса. Он используется для работы с асинхронными операциями: сетевыми запросами, чтением файлов, таймерами и любыми действиями, результат которых появляется не сразу.
Главная идея — отделить запуск асинхронной операции от обработки её результата. Вместо того чтобы передавать колбэки внутрь функции, мы получаем объект, на который можно «подписаться» через методы .then(), .catch() и .finally().
Три состояния промиса
Promise всегда находится в одном из трёх состояний:
- pending (ожидание) — начальное состояние, операция ещё не завершена.
- fulfilled (выполнен) — операция завершилась успешно, промис получил значение.
- rejected (отклонён) — операция завершилась с ошибкой.
Переход из pending в fulfilled или rejected называется settled (улажен) и происходит только один раз. После этого состояние и значение промиса больше не меняются.
Создание промиса
Промис создаётся через конструктор new Promise(), в который передаётся функция-исполнитель с двумя аргументами: resolve и reject.
const promise = new Promise((resolve, reject) => {
// имитируем асинхронную операцию
setTimeout(() => {
const success = true;
if (success) {
resolve('Данные получены');
} else {
reject(new Error('Что-то пошло не так'));
}
}, 1000);
});
Методы для работы с промисом
.then(onFulfilled, onRejected)— регистрирует обработчики успеха и ошибки..catch(onRejected)— обработчик только для ошибок (эквивалент.then(null, onRejected))..finally(onFinally)— выполняется в любом случае, удобно для очистки ресурсов.
Каждый из этих методов возвращает новый промис, что позволяет строить цепочки.
fetch('/api/user')
.then((response) => response.json())
.then((user) => console.log(user.name))
.catch((error) => console.error('Ошибка:', error))
.finally(() => console.log('Запрос завершён'));
Статические методы
Класс Promise предоставляет полезные статические методы для работы с группами промисов:
Promise.all([...])— ждёт все промисы; падает, если хотя бы один отклонён.Promise.allSettled([...])— ждёт завершения всех, возвращает массив результатов.Promise.race([...])— возвращает результат первого завершившегося промиса.Promise.any([...])— возвращает первый успешный промис.Promise.resolve(value)иPromise.reject(reason)— создают уже улаженный промис.
Микрозадачи и event loop
Обработчики .then/.catch/.finally выполняются как микрозадачи (microtasks). Это значит, что они запускаются после текущего синхронного кода, но раньше любых макрозадач (например, setTimeout). Понимание этой очерёдности важно для отладки асинхронного кода.
Связь с async/await
Синтаксис async/await — это «синтаксический сахар» над промисами. Функция, помеченная async, всегда возвращает промис, а await приостанавливает выполнение до его улаживания, делая асинхронный код визуально похожим на синхронный.
Что хочет услышать интервьюер
Определение Promise как объекта, представляющего результат будущей асинхронной операции
Перечисление трёх состояний: pending, fulfilled, rejected — и понимание, что переход необратим
Знание методов .then(), .catch(), .finally() и возможность строить цепочки
Понимание статических методов: Promise.all, allSettled, race, any
Связь промисов с async/await и понимание, что обработчики — это микрозадачи
Пример: Создание и использование промиса
// функция, возвращающая промис с задержкой
function delay(ms: number): Promise<string> {
return new Promise((resolve, reject) => {
if (ms < 0) {
reject(new Error('Отрицательная задержка недопустима'));
return;
}
setTimeout(() => resolve(`Прошло ${ms} мс`), ms);
});
}
// использование через цепочку .then
delay(500)
.then((message) => console.log(message))
.catch((error) => console.error(error.message))
.finally(() => console.log('Готово'));
Пример: Параллельное выполнение с Promise.all и allSettled
// загружаем несколько ресурсов параллельно
async function loadDashboard() {
try {
// Promise.all падает при первой же ошибке
const [user, posts] = await Promise.all([
fetch('/api/user').then((r) => r.json()),
fetch('/api/posts').then((r) => r.json()),
]);
console.log(user, posts);
} catch (error) {
console.error('Один из запросов упал:', error);
}
// allSettled дождётся всех, ошибки не прерывают остальные
const results = await Promise.allSettled([
fetch('/api/a'),
fetch('/api/b'),
]);
results.forEach((result) => {
if (result.status === 'fulfilled') {
console.log('OK:', result.value);
} else {
console.warn('Ошибка:', result.reason);
}
});
}
Типичные ошибки
Путают вызов resolve/reject с возвратом значения из исполнителя — return не влияет на состояние промиса
Забывают про .catch() и теряют ошибки, получая UnhandledPromiseRejection
Считают, что промис можно «отменить» или повторно изменить состояние после settle
Не понимают разницу между Promise.all и Promise.allSettled, теряя данные при одной ошибке
Возвращают из .then() не значение или промис, а сам объект промиса в обёртке, ломая цепочку


