Promise глубоко
Промис изнутри: три состояния, синхронный executor, цепочки и правильная обработка ошибок.
Promise — объект-обещание будущего значения, который находится в одном из трёх состояний: pending, fulfilled или rejected.
Состояния и неизменность
Промис создаётся в состоянии pending (ожидание). Один раз он может перейти либо в fulfilled (через resolve), либо в rejected (через reject) — и больше состояние не меняется. Повторные вызовы resolve/reject игнорируются.
Функцию, которую вы передаёте в new Promise, называют executor. Важная деталь: она запускается синхронно, прямо в момент создания промиса. А вот колбэки .then — всегда асинхронно (как микрозадачи):
console.log("до new Promise");
new Promise((resolve) => {
console.log("внутри executor (синхронно)");
resolve();
}).then(() => console.log("then (асинхронно, microtask)"));
console.log("после new Promise");Вывод:
до new Promise внутри executor (синхронно) после new Promise then (асинхронно, microtask)
Цепочки: каждый then возвращает новый промис
То, что вы вернёте из .then, становится значением следующего звена. Если вернуть обычное значение — оно прокинется дальше; если вернуть промис — цепочка дождётся его.
const p = new Promise((resolve, reject) => {
const ok = true;
if (ok) resolve(10);
else reject(new Error("сломалось"));
});
p.then(x => x * 2)
.then(x => x + 1)
.then(x => console.log("результат:", x));Вывод:
результат: 21
Значение прошло путь 10 → 20 → 21. Каждое звено получило результат предыдущего.
Обработка ошибок: один catch на всю цепочку
Ошибка (или reject) «проваливается» вниз по цепочке мимо всех .then, пока не встретит .catch. После обработки цепочка продолжается в нормальном режиме:
Promise.resolve(5)
.then(x => { throw new Error("ой"); })
.then(x => console.log("это пропустится"))
.catch(err => console.log("поймали:", err.message))
.then(() => console.log("идём дальше"));Вывод:
поймали: ой идём дальше
Промежуточный .then со словами «это пропустится» был проигнорирован, потому что цепочка была в состоянии ошибки. .catch её погасил, и последний .then снова выполнился.
Частые ошибки
| Ошибка | Почему плохо |
Забыть return внутри .then | Следующее звено получит undefined, а вложенный промис не дождётся |
Нет .catch в конце | Ошибка станет «unhandled rejection» и может молча потеряться |
Вкладывать .then внутрь .then | «Лесенка» вместо плоской цепочки — теряется главное преимущество промисов |
Итог
- Промис проходит pending → fulfilled/rejected ровно один раз.
- Executor синхронен,
.then— микрозадача. - Цепочка плоская; один
.catchв конце ловит ошибки всех звеньев выше.