Перейти к содержимому

Promise Anatomy

Promise — конечный автомат с тремя состояниями: pending → fulfilled | rejected; переход необратим, а все .then()-колбэки всегда асинхронны (ставятся в microtask queue), даже если промис уже resolved — знание этих инвариантов обязательно на senior-собесе.

// Состояния и необратимость перехода
const p = new Promise((resolve, reject) => {
console.log('executor: sync'); // выполняется синхронно
resolve(42);
resolve(99); // игнорируется — уже fulfilled
reject('err'); // тоже игнорируется
});
p.then(v => console.log('value:', v));
console.log('after .then()');
// Порядок вывода:
// executor: sync
// after .then()
// value: 42 ← microtask, выполняется после sync-кода
// .then() возвращает НОВЫЙ промис — цепочка это монада
Promise.resolve(1)
.then(v => v + 1) // fulfilled(2)
.then(v => { throw new Error('!'); }) // → rejected
.then(v => console.log('skip')) // пропускается
.catch(e => {
console.log('caught:', e.message); // caught: !
return 'recovered';
})
.then(v => console.log(v)); // recovered
// Promise-инспекция: нет нативного метода — используйте race
function getState(p) {
const sentinel = {};
return Promise.race([p, Promise.resolve(sentinel)]).then(
v => (v === sentinel ? 'pending' : 'fulfilled'),
() => 'rejected'
);
}
const pending = new Promise(() => {});
const resolved = Promise.resolve(1);
getState(pending).then(console.log); // 'pending'
getState(resolved).then(console.log); // 'fulfilled'
// Нет .isPending() / .isFulfilled() — только через side-channel

Итог: Promise — иммутабельный контейнер результата с async-доставкой через microtask queue; цепочка .then() формирует монадический pipe, каждый шаг которого возвращает новый промис.