Что такое promise в javascript

Что такое promise в javascript

Promise – это встроенный объект JavaScript, представляющий результат асинхронной операции, которая может завершиться успешно (fulfilled), с ошибкой (rejected) или остаться в состоянии ожидания (pending). Основное назначение – управление асинхронным кодом без вложенности обратных вызовов.

Promise создаётся через конструктор new Promise, который принимает функцию с двумя аргументами: resolve и reject. Внутри этой функции происходит основная операция, например, запрос к серверу или чтение файла. В случае успеха вызывается resolve(value), при ошибке – reject(error).

Для обработки результата используется метод .then(), который принимает колбэк при успешном завершении. Метод .catch() подключается к цепочке для перехвата ошибок. Завершающий метод .finally() выполняется независимо от исхода операции. Такая структура упрощает чтение кода и избегает каскадных вложенных функций.

Promise не исполняется немедленно – он запускается в момент создания. Важно учитывать, что один и тот же Promise не может изменить своё состояние после первого вызова resolve или reject. Это делает его надёжным инструментом для работы с однократными асинхронными действиями.

В реальных задачах Promises используются с API, которые возвращают отложенные результаты: fetch, setTimeout (обёрнутый вручную), Web APIs. Для последовательных действий применяется цепочка .then(), а для параллельных – методы Promise.all() и Promise.race().

Как создать Promise и что передаётся в конструктор

Как создать Promise и что передаётся в конструктор

resolve(value) переводит промис в состояние «исполнен» (fulfilled) с результатом value. reject(reason) переводит его в состояние «отклонён» (rejected) с причиной reason.

Executor должен выполнять асинхронную или синхронную операцию и вызывать одну из этих функций в зависимости от результата. Если при выполнении executor возникает исключение, промис автоматически отклоняется с этим исключением как причиной.

Пример создания промиса:

const promise = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', '/data.json');
xhr.onload = () => {
if (xhr.status === 200) {
resolve(xhr.responseText);
} else {
reject(xhr.status);
}
};
xhr.onerror = () => reject('Network error');
xhr.send();
});

В этом примере функция executor инкапсулирует логику запроса и вызывает resolve или reject в зависимости от результата. Promise не предоставляет никакой встроенной логики ожидания – всё зависит от того, как написан executor.

Что означает состояние Promise и как оно меняется

Что означает состояние Promise и как оно меняется

Promise имеет три состояния: pending, fulfilled и rejected. Начальное состояние – pending. Оно означает, что результат ещё не известен. В этом состоянии объект ожидает завершения асинхронной операции.

Переход из pending в fulfilled происходит при вызове функции resolve внутри executor. Это означает успешное завершение операции. Значение, переданное в resolve, становится результатом Promise и доступно в методе then.

Переход в rejected происходит при вызове reject или при исключении внутри executor. В этом случае результатом становится объект ошибки, доступный в методе catch.

После перехода из pending в одно из финальных состояний Promise считается завершённым. Повторные вызовы resolve или reject игнорируются. Состояние Promise необратимо.

Проверить текущее состояние Promise напрямую нельзя. Вместо этого используют then, catch и finally для обработки результата или ошибки после завершения.

Как использовать методы then, catch и finally

Как использовать методы then, catch и finally

then используется для обработки успешного выполнения Promise. Метод принимает один аргумент – функцию, которая получает результат выполнения. Если результат не требуется, можно опустить параметр:

fetch('/data.json')
.then(response => response.json())
.then(data => {
console.log(data);
});

Если в цепочке then происходит ошибка, она передаётся следующему catch. Этот метод нужен для обработки отклонений или исключений:

fetch('/data.json')
.then(response => response.json())
.catch(error => {
console.error('Ошибка загрузки:', error);
});

finally вызывается в любом случае – после завершения Promise, независимо от того, завершился он успешно или с ошибкой. Метод не получает аргументов:

fetch('/data.json')
.then(response => response.json())
.catch(error => {
console.error(error);
})
.finally(() => {
console.log('Запрос завершён');
});

Методы можно комбинировать в одной цепочке. Если then возвращает новый Promise, следующий then будет ждать его завершения. Важно не смешивать синхронный и асинхронный код в одном обработчике – это затрудняет отладку. Всегда возвращайте данные или ошибки явно, чтобы сохранить предсказуемость цепочки.

В чём разница между цепочкой Promise и вложенными вызовами

В чём разница между цепочкой Promise и вложенными вызовами

Вложенные вызовы приводят к увеличению уровня отступов и ухудшают читаемость. Каждый следующий `.then()` находится внутри предыдущего, из-за чего структура кода напоминает «пирамиду». Это затрудняет отладку и повышает риск ошибок при обработке исключений, поскольку блок `.catch()` внизу может не перехватить исключение из внутреннего блока, если промис не возвращается явно.

Цепочка промисов избавляет от лишних отступов и сохраняет линейную структуру. Каждый `.then()` возвращает результат, доступный следующему в цепи. Такой подход облегчает отладку, позволяет централизованно обрабатывать ошибки через единый `.catch()` и сохраняет порядок выполнения операций. Возврат значения или нового промиса обязателен, иначе следующий `.then()` получит `undefined`.

При использовании вложенных вызовов нет автоматической передачи значения наружу. Если не возвращать промис из внутреннего блока, внешний `.then()` продолжит выполнение, не дожидаясь завершения вложенного. В цепочке такого не происходит – управление переходит к следующему звену только после завершения текущего.

Выбор в пользу цепочки снижает вероятность логических ошибок, связанных с асинхронностью, и делает поведение предсказуемым.

Как обрабатывать несколько Promise одновременно с помощью Promise.all и Promise.race

Метод Promise.all позволяет запустить несколько промисов параллельно и получить результат только тогда, когда все они завершатся успешно. Если хотя бы один завершится с ошибкой, весь Promise.all перейдёт в состояние rejected.

Пример использования:

const p1 = fetch('/данные1');
const p2 = fetch('/данные2');
const p3 = fetch('/данные3');
Promise.all([p1, p2, p3])
.then(responses => Promise.all(responses.map(r => r.json())))
.then(data => {
// массив с результатами всех трёх запросов
console.log(data);
})
.catch(error => {
// ошибка, если хотя бы один запрос не удался
console.error(error);
});

Метод Promise.race возвращает результат первого завершившегося промиса – независимо от того, был он выполнен успешно или с ошибкой. Это удобно, когда нужно получить данные как можно быстрее или реализовать таймаут ожидания.

Пример использования таймаута:

const fetchData = fetch('/ресурс');
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Превышено время ожидания')), 3000)
);
Promise.race([fetchData, timeout])
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));

Если нужно дождаться всех промисов, но получить результат хотя бы тех, которые завершились успешно, используйте Promise.allSettled. Он возвращает массив объектов с полями status и value или reason.

Что происходит при выбросе исключения внутри Promise

Что происходит при выбросе исключения внутри Promise

Когда в теле функции, переданной в конструктор Promise, возникает исключение, это исключение автоматически передается в цепочку обработчиков Promise.

Пример:


new Promise((resolve, reject) => {
throw new Error('Что-то пошло не так');
})
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error);
});

В данном примере исключение, выброшенное в блоке, передается в метод catch, который обрабатывает ошибку. Это поведение аналогично тому, как работает обработка ошибок в синхронных функциях, но в асинхронном контексте Promise.

Обработка исключений в Promise зависит от того, как структурирована цепочка обработки:

  • Если ошибка не обработана с помощью catch, она будет игнорироваться и не повлияет на выполнение других промисов.
  • При использовании then для обработки, ошибка будет передана следующему catch или другому then, если тот возвращает промис с ошибкой.
  • Если в then выбрасывается исключение, оно передается в цепочку к следующему catch.

Пример с несколькими then:


new Promise((resolve, reject) => {
throw new Error('Ошибка на первом шаге');
})
.then(() => {
return 'Данные';
})
.catch(error => {
console.error('Обработано в catch:', error.message);
});

При выбросе исключения в первом then, оно передается в catch, который обрабатывает ошибку. Без catch ошибка «поглотит» выполнение и не будет видна.

Если же ошибка выбрасывается в асинхронной функции внутри Promise, важно помнить, что её обработка отличается от обычных синхронных исключений, и требуется использование catch для правильного перехвата.

Совет: всегда обрабатывайте ошибки в цепочках Promise, иначе это приведет к необработанным исключениям и непредсказуемым результатам.

Вопрос-ответ:

Что такое Promise в JavaScript?

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

Как Promise помогает при работе с асинхронным кодом?

Promise упрощает работу с асинхронными функциями, такими как запросы к серверу, таймеры или чтение файлов. Он позволяет избегать «адской пирамиды» колбеков (callback hell), улучшая читаемость и управление состоянием асинхронных операций. Вместо вложенных функций Promise использует методы `then` и `catch`, что делает код более чистым и понятным.

Что такое Promise в JavaScript и зачем он нужен?

Promise — это объект, который представляет собой значение, которое может быть доступно в будущем. Он используется для работы с асинхронным кодом, например, при выполнении запросов на сервер или работе с таймерами. Promise помогает избежать «адского колбэка» (callback hell), так как позволяет обрабатывать асинхронные операции более удобно, используя методы `.then()` и `.catch()`. Promise может находиться в одном из трех состояний: ожидающее (pending), выполненное (fulfilled) и отклонённое (rejected).

Как работает Promise в JavaScript?

Promise создаётся с помощью конструктора `new Promise()`. Он принимает функцию с двумя параметрами: `resolve` и `reject`. Внутри этой функции выполняется асинхронная операция, и в зависимости от её результата вызывается либо `resolve()` (если операция завершилась успешно), либо `reject()` (если произошла ошибка). Когда промис переходит в состояние `fulfilled` или `rejected`, можно использовать методы `.then()` для успешного результата и `.catch()` для обработки ошибок. Это позволяет строить цепочку вызовов, которые будут выполняться последовательно, один за другим, или обрабатывать ошибки в случае их возникновения.

Ссылка на основную публикацию