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-инспекция: нет нативного метода — используйте racefunction 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, каждый шаг которого возвращает новый промис.