От колбэков к промисам: then, catch, finally
Зачем придумали Promise и как им пользоваться.
Promise — объект, представляющий результат асинхронной операции, который появится в будущем. Имеет три состояния:
pending(ожидание),fulfilled(успех),rejected(ошибка).
Проблема колбэков
Раньше асинхронность строили на колбэках. Вложенные операции превращались в «callback hell» — лесенку из вложенных функций, которую тяжело читать и в которой легко потерять обработку ошибок.
getUser(id, (user) => {
getOrders(user, (orders) => {
getDetails(orders, (details) => {
// лесенка растёт вправо
});
});
});
Промис: then и catch
Промис позволяет выстроить операции в плоскую цепочку. .then обрабатывает успех, .catch — ошибку для всей цепочки сразу.
const promise = new Promise((resolve) => {
resolve(10); // успех со значением 10
});
promise
.then((value) => {
console.log("получили:", value);
return value * 2; // передаём дальше
})
.then((doubled) => {
console.log("удвоили:", doubled);
});
Вывод:
получили: 10 удвоили: 20
Обработка ошибок
Если промис отклонён (reject) или в .then выброшено исключение, управление прыгает в ближайший .catch. .finally выполняется в любом случае.
Promise.reject(new Error("сбой сети"))
.then(() => console.log("не выполнится"))
.catch((err) => console.log("поймали:", err.message))
.finally(() => console.log("finally всегда"));
Вывод:
поймали: сбой сети finally всегда
Цепочка значений
Каждый .then возвращает новый промис. Если вернуть значение — оно станет результатом следующего .then; если вернуть промис — цепочка дождётся его.
Promise.resolve(1)
.then((x) => x + 1)
.then((x) => Promise.resolve(x * 10)) // вернули промис
.then((x) => console.log("итог:", x));
Вывод:
итог: 20
Состояния промиса
| Состояние | Что значит | Обработчик |
| pending | операция идёт | — |
| fulfilled | успех | .then |
| rejected | ошибка | .catch |
Важное свойство, о котором спрашивают: промис неизменяем после разрешения. Как только он стал fulfilled или rejected, его состояние и значение зафиксированы навсегда — повторный resolve ничего не изменит. Поэтому к уже выполненному промису можно добавить .then сколько угодно раз, и он сразу получит сохранённый результат.
Частая ошибка: «забыли вернуть промис»
Типичный баг, который любят показывать на собеседовании: внутри .then вызвали асинхронную операцию, но не вернули её. Тогда цепочка не дождётся вложенного промиса, и порядок «поедет». Правило простое: если в .then вы запускаете что-то асинхронное — обязательно return этот промис, чтобы внешняя цепочка его дождалась. Это же правило лежит в основе того, почему async/await (следующий урок) читается проще: там ожидание выражается явным await.
Итог
- Промис избавляет от вложенных колбэков, выстраивая плоскую цепочку.
.then— успех,.catch— ошибка всей цепочки,.finally— всегда.- Каждый
.thenвозвращает промис; вернёшь промис — цепочка его дождётся.