Может ли Promise одновременно зарезолвиться и зареджектиться в JavaScript?
Что проверяют
Знаете ли вы, что состояние промиса меняется один раз, и различаете ли термины resolved и fulfilled. Следом часто показывают executor с resolve(), reject() и throw подряд и просят предсказать вывод.
Как отвечать
Нет. У промиса три состояния: pending, fulfilled, rejected. Выход из pending происходит один раз, после этого промис считается settled, и его состояние неизменно. Повторные вызовы resolve и reject игнорируются молча, без ошибки. Исключение, брошенное в executor после resolve(), тоже пропадает: промис уже выполнен, и его reject ничего не меняет.
Хороший ответ добавляет три тонкости:
- resolved не равно fulfilled: по спецификации resolved значит «судьба решена». Если передать в
resolveдругой промис или thenable, внешний промис остаётсяpendingи повторяет его исход.resolve(Promise.reject(err))в итоге даст rejected. Так что «зарезолвился, но отклонился» бывает, просто не одновременно; resolveэто неreturn: код после него в executor продолжает выполняться, поэтому после раннегоresolveставятreturn;- колбэки асинхронны: обработчики
thenиcatchвыполняются в очереди микрозадач, даже если промис уже settled.
Та же гарантия действует для Promise.withResolvers() из ES2024, где resolve и reject вынесены наружу: вызвать можно оба, сработает первый. Если нужен исход каждого из нескольких промисов, есть Promise.allSettled().
Во фронтенде это пригождается в гонках запросов: промис от устаревшего fetch всё равно завершится, и защищаться нужно AbortController или проверкой актуальности ответа, а не надеждой на повторный reject.
Где спотыкаются
Считают, что второй вызов reject бросит исключение или попадёт в catch. Он просто теряется, и ошибку никто не увидит.
Путают resolved и fulfilled, поэтому не могут объяснить, почему resolve(rejectedPromise) уходит в catch.
Пишут new Promise(async (resolve, reject) => { ... }). Исключение внутри async-функции не превращается в reject внешнего промиса: он зависает в pending, а в консоли появляется необработанное отклонение.