
Современные веб-приложения активно используют асинхронные операции: загрузка данных с сервера, задержки, работа с файлами и другими внешними источниками. Чтобы эффективно управлять такими процессами, в 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, который работает поверх промисов, но позволяет писать асинхронный код в синхронном стиле.