JavaScript Promise API
Promise API в JavaScript: Promise.all, allSettled, race, any, resolve и reject. Сравнение fast-fail и allSettled с примерами и таблицей выбора метода.
Класс Promise предоставляет несколько статических методов для комбинирования и создания промисов. Вместо того чтобы вручную выстраивать несколько цепочек .then(), вы передаёте массив промисов одному комбинатору и получаете единственный промис, который завершается, когда группа достигает определённого состояния.
На этой странице рассматриваются четыре комбинатора — Promise.all, Promise.allSettled, Promise.race и Promise.any — а также два вспомогательных метода создания Promise.resolve и Promise.reject. Если вы только знакомитесь с промисами, начните с раздела JavaScript: Промисы.
В приведённых ниже примерах используются
.then()/.catch(), чтобы поток управления был явным. В реальном коде результат обычно читается с помощьюasync/await.
Выбор подходящего комбинатора
| Метод | Выполняется, когда… | Отклоняется, когда… | Типичное применение |
|---|---|---|---|
Promise.all | все промисы выполнены | любой промис отклонён (fast-fail) | Нужны все результаты, и один сбой должен прервать всё |
Promise.allSettled | все промисы завершены (никогда не отклоняется) | — | Нужен каждый результат, независимо от успеха или ошибки |
Promise.race | первый промис завершён (выполнен или отклонён) | первый промис отклоняется первым | Таймауты, «кто ответил первым — тот победил» |
Promise.any | первый промис выполнен | все промисы отклонены | Первый успешный результат, игнорируя отдельные ошибки |
Ключевое различие: Promise.all завершается немедленно при ошибке (fast-fail) — он отклоняется в тот же момент, когда отклоняется любой входной промис, даже если другие ещё в состоянии ожидания. Если вместо этого нужно дождаться каждого промиса независимо от исхода, используйте Promise.allSettled.
Использование Promise.all для параллельных задач
Promise.all — незаменимый метод для одновременной обработки нескольких промисов. Когда нужно выполнить несколько асинхронных операций и продолжить только после того, как все они успешно завершатся, Promise.all — именно то, что нужно.
Как применять Promise.all
Ниже приведён пример, демонстрирующий, как использовать Promise.all для одновременной обработки нескольких API-запросов:
В этом примере Promise.all принимает массив промисов и разрешается в массив их результатов в том же порядке, что и входные данные (а не в порядке завершения). Если какой-либо промис отклоняется, Promise.all немедленно отклоняется с причиной этого первого отказа — результаты остальных отбрасываются. Смотрите раздел Обработка ошибок в промисах, чтобы узнать, как восстановиться после таких сбоев.
Освоение Promise.allSettled
В отличие от Promise.all, метод Promise.allSettled возвращает промис, который разрешается после того, как все переданные промисы либо выполнились, либо были отклонены, — с массивом объектов, каждый из которых описывает исход соответствующего промиса.
Пример использования Promise.allSettled
Вот как можно применить Promise.allSettled:
Примечание: Promise.allSettled никогда не отклоняется. Он всегда разрешается с массивом объектов результатов, каждый из которых содержит свойство status ('fulfilled' или 'rejected') и либо свойство value, либо reason.
Этот метод особенно полезен, когда нужно убедиться, что все промисы доведены до завершения независимо от того, выполнены они или отклонены.
Применение Promise.race
Promise.race — ещё один мощный инструмент, который позволяет обрабатывать несколько промисов, выполняясь или отклоняясь сразу, как только один из промисов в итерируемом объекте выполняется или отклоняется.
Как использовать Promise.race
Ниже приведён практический пример применения Promise.race:
Этот метод идеально подходит для сценариев, где нужен самый быстрый результат среди нескольких асинхронных операций — например, для состязания запроса с промисом-таймаутом. Обратите внимание, что race завершается по первому промису, который завершится, будь то выполнение или отклонение.
Получение первого успешного результата с Promise.any
Promise.any — оптимистичный аналог Promise.race. Он игнорирует отклонения и разрешается со значением первого выполненного промиса. Он отклоняется только в том случае, если все промисы отклонены — тогда выбрасывается AggregateError, свойство .errors которого содержит все отдельные причины.
Как использовать Promise.any
Используйте Promise.any, когда у вас несколько источников одних и тех же данных (например, зеркальные серверы) и важен лишь первый, который ответит успешно.
Создание промисов с помощью resolve и reject
Promise.resolve(value) и Promise.reject(reason) — это сокращения для создания уже завершённого промиса без шаблонного кода new Promise(executor).
Promise.resolve(value)возвращает промис, уже выполненный со значениемvalue. Еслиvalueсамо является thenable, оно «принимается» и отслеживается.Promise.reject(reason)возвращает промис, уже отклонённый с причинойreason.
Эти вспомогательные методы часто используются для возврата кэшированного значения из иначе асинхронной функции или для запуска цепочки .then().
Создание полифила для Promise.allSettled
Не все окружения поддерживают Promise.allSettled нативно. Поэтому реализация полифила позволяет обеспечить совместимость с различными окружениями JavaScript.
Полифил для Promise.allSettled
Вот как можно создать простой полифил:
Этот полифил обеспечивает базовую функциональность, при которой каждый промис обрабатывается индивидуально и разрешается с соответствующим исходом, эффективно воспроизводя поведение allSettled.
Применяя эти продвинутые техники работы с промисами и понимая механику полифилов, вы сможете вывести свой JavaScript-код на новый уровень. Эти методы не только повышают надёжность кода, но и дают точный контроль над асинхронными операциями, открывая путь к созданию более надёжных веб-приложений.