
Современные веб-приложения активно используют асинхронные операции: загрузка данных с сервера, задержки, работа с файлами и другими внешними источниками. Чтобы эффективно управлять такими процессами, в JavaScript был введён специальный механизм — промисы (Promises).
В этой статье мы подробно разберёмся, что такое промисы, как они работают, и как их использовать для написания чистого и читаемого асинхронного кода.
—
Что такое промис?
Промис (Promise) — это объект, представляющий результат асинхронной операции, который может быть доступен сейчас, позже или никогда.
Промис создаёт мост между началом асинхронной операции и моментом, когда она завершится — успешно или с ошибкой. Вместо вложенных коллбеков (что часто ведёт к «адскому коду»), промисы позволяют выстраивать аккуратную и понятную цепочку обработки данных.
—
Состояния промиса
Каждый промис имеет одно из трёх состояний:
pending (ожидание) — начальное состояние, операция ещё не завершена.
fulfilled (выполнен) — операция завершена успешно, есть результат.
rejected (отклонён) — операция завершилась с ошибкой.
Когда промис переходит в состояние fulfilled или rejected, он становится неизменяемым — то есть результат остаётся фиксированным.
—
Создание промиса
Создать промис можно с помощью конструктора new Promise():
const promise = new Promise((resolve, reject) => {
// Выполняем асинхронную операцию
setTimeout(() => {
const success = true;
if (success) {
resolve(«Операция выполнена успешно!»);
} else {
reject(«Произошла ошибка.»);
}
}, 1000);
});
Здесь:
resolve вызывается при успешном завершении,
reject — при ошибке.
—
Обработка результата
Чтобы обработать результат промиса, используются методы .then() и .catch():
promise
.then(result => {
console.log(«Результат:», result);
})
.catch(error => {
console.error(«Ошибка:», error);
});
Метод .then() срабатывает при resolve(), а .catch() — при reject().
—
Цепочка промисов
Одна из мощных возможностей — это создание цепочек .then():
new Promise((resolve) => {
setTimeout(() => resolve(2), 1000);
})
.then(result => {
return result * 2; // 4
})
.then(result => {
return result + 3; // 7
})
.then(result => {
console.log(«Финальный результат:», result); // 7
});
Каждое новое значение передаётся в следующий .then(). Это позволяет пошагово обрабатывать данные без вложенных функций.
—
Обработка ошибок
Ошибки можно отлавливать через .catch():
fetchData()
.then(processData)
.then(displayData)
.catch(error => {
console.error(«Произошла ошибка:», error);
});
Если ошибка произойдёт на любом этапе цепочки, она попадёт в catch.
—
Пример функции с промисом
function getUserData(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (userId > 0) {
resolve({ id: userId, name: «Алексей» });
} else {
reject(«Некорректный ID пользователя»);
}
}, 1000);
});
}
getUserData(1)
.then(user => {
console.log(«Пользователь:», user);
})
.catch(error => {
console.error(«Ошибка:», error);
});
—
Промисы против коллбеков
До появления промисов асинхронность реализовывалась через вложенные функции (коллбеки), что выглядело неаккуратно:
loadData(function(data) {
processData(data, function(result) {
displayResult(result);
});
});
С промисами код становится более чистым и линейным:
loadData()
.then(processData)
.then(displayResult)
.catch(error => console.error(error));
—
Заключение
Промисы — это мощный инструмент в арсенале JavaScript-разработчика. Они позволяют эффективно управлять асинхронными операциями, избегая «callback hell» и упрощая структуру кода. Освоив промисы, вы сможете создавать более надёжные и читаемые веб-приложения.
Если вы хотите упростить работу с промисами ещё больше — изучите async/await, который работает поверх промисов, но позволяет писать асинхронный код в синхронном стиле.