JavaScript WindowsLinuxmacOS

JavaScript: промис остаётся pending из-за пропущенного resolve

  • Обновлено
  • Чтение ≈ 3 минуты

Краткий ответ

Promise остаётся pending: найдите ветку, которая не вызывает resolve или reject, проследите асинхронные исключения и завершите все исходы операции.

В этой статье
  1. Что происходит и как распознать неисправность
  2. Как отличить причины
  3. Пошаговая диагностика и исправление
  4. Команды и примеры для проверки
  5. Как проверить результат и что делать дальше

#Что происходит и как распознать неисправность

Если функция возвращает new Promise, но на одном пути выполнения не вызывается ни resolve, ни reject, ожидание await продолжается бесконечно. Ошибка отличается от HTTP-задержки: даже когда исходная операция закончена, обещание не переходит в состояние fulfilled/rejected.

#Как отличить причины

Возможная причинаКак узнатьЧто делать
Ветка if выходит без завершенияРанний return или else не вызывает resolve/reject.В определённом сценарии then/catch вообще не исполняются.Обработайте все ветки, при ошибке вызывайте reject.
Исключение в отложенном обработчикеОшибка внутри setTimeout/event-handler не всегда связана с внешним исполнителем Promise.В консоли есть uncaught error, Promise всё ещё pending.Используйте reject внутри обработчика либо async-функцию без лишнего new Promise.
Событие никогда не приходитОбещание ждёт событие, которое не гарантировано.Незавершённая загрузка или отсутствующий listener.Добавьте обоснованный таймаут, очистку и отказ по ошибке.

#Пошаговая диагностика и исправление

  1. Проверьте, где ожидается PromiseВ редакторе найдите строку await myFunction() или .then(...), после которой нет вывода. Добавьте временные console.log("до") и console.log("после") вокруг ожидания, а внутри исполнителя Promise — лог по каждой ветке. Воспроизведите случай, когда после не появляется; не печатайте приватные данные.
  2. Найдите все exit-пути внутри new PromiseОткройте функцию, выполняющую return new Promise((resolve, reject) => {...}). Проверьте if/else, return, обработчики ошибок и события: в каждом конечном исходе должен быть вызов resolve или reject. Само return из callback не разрешает Promise. Отметьте конкретную ветку, где управление теряется.
  3. Разберите ошибки в отложенных callbackЕсли внутри setTimeout, обработчика события или callback библиотека может бросить исключение, перехватите его в самом callback и передайте в reject. Исключение, возникшее после завершения конструктора Promise, не обязательно попадёт в автоматический reject его исполнителя.
  4. Удалите лишнюю обёртку, если уже есть PromiseЕсли fetch, async-функция или библиотечный вызов уже возвращают Promise, вместо нового new Promise просто return fetch(...) или return await ... внутри функции async function. return await применяйте, например, когда нужно перехватить ошибку локальным try/catch. Это упрощает обработку ошибок и исключает забытый resolve.
  5. Добавьте таймаут только для операции, которая может зависнутьДля внешнего запроса используйте AbortController и допустимое бизнес-правилами время ожидания; передавайте его signal в fetch. По истечении срока отменяйте запрос, выводите ясную ошибку, очищайте таймер и обработчики. Не выбирайте произвольные 1–2 секунды для операций, которые законно выполняются дольше.
  6. Привяжите reject к реальному состоянию ошибкиВ случае отказа файла или запроса сохраняйте причину (reject(error)), а не resolve(undefined), если отсутствие результата является ошибкой по контракту. Вызывающий код должен иметь try/catch для await либо .catch. Если ошибку намеренно обрабатывают выше, не скрывайте её пустым обработчиком.
  7. Проверьте все исходы и очисткуВ тестовой среде смоделируйте удачную операцию, сетевую ошибку, ранний return и таймаут. Для каждого сценария await должен завершаться значением либо управляемым исключением, а слушатели/таймеры должны очищаться. При неверной бизнес-логике верните копию функции и согласуйте контракт завершения.

#Команды и примеры для проверки

Текст
Выполняйте в консоли браузера или в отдельном тестовом файле; getResult(false) завершится отклонением вместо вечного pending.
function getResult(enabled) {
  return new Promise((resolve, reject) => {
    if (!enabled) {
      reject(new Error("Операция запрещена"));
      return;
    }
    setTimeout(() => resolve("готово"), 100);
  });
}
getResult(true).then(console.log).catch(console.error);

#Как проверить результат и что делать дальше

Промис больше не остаётся pending в завершившейся операции: любой конечный исход обрабатывается как успех, ошибка или отмена. Не подменяйте исправление постоянным опросом состояния без предела.

Источники и обновления

Последнее обновление статьи: 2 ноября 2026. Версии программ и интерфейсы меняются — если шаги не совпадают с вашей версией, сверяйтесь с документацией производителя.