Promise – это специальный объект, который содержит своё состояние. Вначале pending
(«ожидание»), затем – одно из: fulfilled
(«выполнено успешно») или rejected
(«выполнено с ошибкой»).
На promise
можно навешивать колбэки двух типов:
onFulfilled
– срабатывают, когда promise
в состоянии «выполнен успешно».onRejected
– срабатывают, когда promise
в состоянии «выполнен с ошибкой».Способ использования, в общих чертах, такой:
promise
и возвращает его.promise
, навешивает на него обработчики.promise
в состояние fulfilled
(с результатом) или rejected
(с ошибкой). При этом автоматически вызываются соответствующие обработчики во внешнем коде.Для обработки успешного ответа имеется специальный метод then
promise.then(onFulfilled, onRejected)
onFulfilled
– функция, которая будет вызвана с результатом при resolve
.onRejected
– функция, которая будет вызвана с ошибкой при reject
.С его помощью можно назначить как оба обработчика сразу, так и только один:
// onFulfilled сработает при успешном выполнении promise.then(onFulfilled) // onRejected сработает при ошибке promise.then(null, onRejected)
Цепочки промисов
«Чейнинг» (chaining), то есть возможность строить асинхронные цепочки из промисов – пожалуй, основная причина, из-за которой существуют и активно используются промисы.
Например, мы хотим по очереди:
Вот код для этого, использующий функцию httpGet
, описанную выше:
httpGet(...) .then(...) .then(...) .then(...)
При чейнинге, то есть последовательных вызовах .then…then…then
, в каждый следующий then
переходит результат от предыдущего. Вызовы console.log
оставлены, чтобы при запуске можно было посмотреть конкретные значения, хотя они здесь и не очень важны.
Если очередной then
вернул промис, то далее по цепочке будет передан не сам этот промис, а его результат.
В коде выше:
then
возвращает «обычное» значение user
. Это значит, что then
возвратит промис в состоянии «выполнен» с user
в качестве результата. Он станет аргументом в следующем then
.then
возвращает промис (результат нового вызова httpGet
). Когда он будет завершён (может пройти какое-то время), то будет вызван следующий then
с его результатом.then
ничего не возвращает..catch
Для чтобы обработать код ошибки после .then()
можно написать .catch()
.
promise.then().catch()
Это также похоже на обычный try..catch
– в блоке catch
ошибка либо обрабатывается, и тогда выполнение кода продолжается как обычно, либо он делает throw
. Существенное отличие – в том, что промисы асинхронные, поэтому при отсутствии внешнего .catch
ошибка не «вываливается» в консоль и не «убивает» скрипт.
Ведь возможно, что новый обработчик .catch
будет добавлен в цепочку позже.
Использование
Объект Promise служит удобной оберткой для обслуживания асинхронного функционала. Основное назначение Promise создавать цепочки вызовов асинхронных функций.
const myPromise = new Promise((resolve, reject) => { // выполнение асинхронного кода... // resolve(someValue); // вернуть результат как Promise // reject("причина ошибки"); // если произошла ошибка }); myPromise .then((data) => { return myNextPromise(data); }) .then((data2) => { return myNextPromise2(data2); }) .then((data3) => { return myNextPromise3(data3); }) .catch(); // будет вызван в случае ошибки
Грамотное использование промисов позволяет избежать запутанности кода. Тогда програмный код приобретает такой вид:
getUserInfo(1) .then(userData => { return do_something(userData); }) .then(([permissions, userData]) => { return do_something2(permissions, userData); }) .catch(console.log("err"));