Что такое Promise


Promise (обещание) — это встроенный объект в JavaScript, предназначенный для работы с асинхронными операциями. Он представляет значение, которое может быть доступно сейчас, в будущем или никогда, и позволяет писать асинхронный код в более структурированной и читаемой форме, чем традиционные коллбэки.

🔹 Основная идея

Асинхронный код часто сопровождается отложенными результатами (например, запрос на сервер или чтение файла). Promise — это обёртка над этими результатами, которая даёт удобный способ:

  • ждать результата,

  • обработать успех или ошибку,

  • цеплять действия (chain),

  • управлять несколькими параллельными операциями.

🔹 Состояния Promise

Каждый Promise имеет одно из трёх состояний:

  1. Pending (ожидание) — начальное состояние, операция ещё не завершена.

  2. Fulfilled (выполнено) — операция завершена успешно, и результат доступен.

  3. Rejected (отклонено) — операция завершилась с ошибкой.

После перехода из pending в fulfilled или rejected, состояние становится неизменяемым.

🔹 Создание Promise

const promise = new Promise((resolve, reject) => {
// Асинхронная операция
if (успех) {
resolve('результат');
} else {
reject('ошибка');
}
});

Функция-исполнитель принимает два аргумента:
- resolve(value) — вызов при успешном завершении;
- reject(error) — вызов при ошибке.

🔹 Использование .then(), .catch(), .finally()

.then(onFulfilled, onRejected)

Обрабатывает успешное завершение:

promise
.then((result) => {
console.log('Успех:', result);
})
.catch((error) => {
console.log('Ошибка:', error);
});
  • .then() возвращает новый Promise, позволяя создавать цепочки (chaining).

  • .catch() — сокращённая форма .then(null, onRejected).

  • .finally() — вызывается независимо от результата.

promise
.finally(() => console.log('Завершено'))
.then((result) => console.log(result))
.catch((err) => console.log(err));

🔹 Цепочка промисов

fetchData()
.then((data) => processData(data))
.then((result) => sendToServer(result))
.then(() => console.log('Готово!'))
.catch((err) => console.error('Ошибка:', err));

Каждое звено в цепи .then() обрабатывает результат предыдущего.

🔹 Асинхронная ошибка

Если в .then() или другом обработчике возникает ошибка, она автоматически переходит в catch():

promise
.then(() => {
throw new Error("Ошибка!");
})
.catch((e) => console.log(e.message)); // Выведет: "Ошибка!"

🔹 Статические методы Promise

Promise.resolve(value)

Создаёт успешно завершённый промис с заданным значением.

Promise.resolve(5).then((x) => console.log(x)); // 5
Promise.reject(error)

Создаёт промис, завершённый с ошибкой.

Promise.reject('ошибка').catch((e) => console.log(e)); // ошибка
Promise.all(iterable)

Ожидает выполнения всех промисов. Возвращает промис с массивом результатов. Если хотя бы один промис отклонён — Promise.all завершится с ошибкой.

Promise.all(\[p1, p2, p3\])
.then((\[r1, r2, r3\]) => console.log(r1, r2, r3))
.catch((err) => console.log('Ошибка:', err));
Promise.allSettled(iterable)

Ожидает выполнения всех промисов, но не отклоняется даже при ошибках. Возвращает массив объектов с результатами:

Promise.allSettled(\[
Promise.resolve('OK'),
Promise.reject('Fail')
\]).then(console.log);
Promise.race(iterable)

Возвращает результат первого завершившегося промиса — независимо от успеха или ошибки.

Promise.race(\[p1, p2\])
.then((result) => console.log('Победил:', result));
Promise.any(iterable)

Ожидает первый успешный промис. Если все завершились с ошибкой, то промис отклоняется с AggregateError.

Promise.any(\[
Promise.reject('e1'),
Promise.resolve('успех')
\]).then(console.log);

🔹 Пример: имитация асинхронного запроса

function fakeApiCall(success = true) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (success) {
resolve('Данные получены');
} else {
reject('Ошибка при получении данных');
}
}, 1000);
});
}
fakeApiCall()
.then(console.log)
.catch(console.error);

🔹 Использование с async/await

Хотя async/await является синтаксическим сахаром над Promise, они тесно связаны:

async function getData() {
try {
const result = await fakeApiCall();
console.log(result);
} catch (e) {
console.error(e);
}
}

await приостанавливает выполнение функции до завершения промиса и возвращает его результат или бросает ошибку, если промис отклонён.

🔹 Внутреннее устройство промиса

В JavaScript движках (например, V8), Promise реализован через:

  • очереди микрозадач (Microtasks Queue);

  • замыкания для хранения состояния;

  • коллбеки, сохраняемые до момента завершения промиса.

Каждый then() не исполняется мгновенно, а добавляется в очередь после текущего выполнения скрипта, что гарантирует предсказуемый порядок исполнения.

🔹 Проблемы и ограничения

  • Promise не может быть отменён (нужно использовать AbortController).

  • Не обрабатывает асинхронные итерации (решается через async generators).

  • Ошибки могут "теряться", если .catch() не добавлен.

  • Может усложнить отладку при глубокой вложенности или небрежной архитектуре.

Таким образом, Promise — мощный инструмент асинхронного программирования в JavaScript, который делает возможным управление отложенными операциями, их комбинацией, обработкой ошибок и построением предсказуемых, безопасных цепочек событий.