> Как отменить или обработать промис в JavaScript (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: TYMY
Стек: JavaScript
> Пример ответа
Короткий ответ
Промис в JavaScript нельзя отменить нативно - у него нет метода .cancel(). Для обработки используют try/catch с async/await или .catch(). Для имитации отмены применяют AbortController (в fetch) или оборачивают промис в reject при флаге отмены. В продакшене часто используют сторонние библиотеки (например, Bluebird с .cancel()) или паттерн с токеном отмены.
Подробное объяснение
Промис по спецификации - это объект с тремя состояниями: pending, fulfilled, rejected. Переход из pending в любое другое состояние необратим. Отмена как четвёртое состояние отсутствует. Это сделано для простоты и предсказуемости цепочек промисов.
Для обработки ошибок и отказов используется .catch() или try/catch в async/await. Если нужно прервать выполнение асинхронной операции, используют AbortController - он передаёт сигнал в fetch или другие API, поддерживающие отмену. Для собственных промисов применяют обёртку с проверкой флага отмены: при установке флага промис реджектится с кастомной ошибкой.
На практике отмена часто реализуется через паттерн "token cancellation": создаётся объект с флагом isCancelled, который проверяется внутри асинхронной функции. Если флаг установлен, функция не выполняет коллбэк resolve, а реджектит промис или просто завершается.
На практике
В современных приложениях (React, Node.js) отмена промисов критична для:
- предотвращения утечек памяти при размонтировании компонента
- отмены устаревших запросов при повторном вызове
- тайм-аутов и прерывания долгих операций
В React для отмены запросов при unmount используют useEffect с cleanup-функцией, где вызывается abort(). В Node.js AbortController применяют для отмены HTTP-запросов, чтения потоков и таймеров.
Для собственных асинхронных функций (не fetch) удобно создать утилиту makeCancelable, которая оборачивает промис и добавляет метод cancel(), реджектящий промис с кастомной ошибкой.
Пример кода
JAVASCRIPT// Отмена fetch через AbortControllerfunction fetchWithCancel(url) {const controller = new AbortController();const promise = fetch(url, { signal: controller.signal });return { promise, cancel: () => controller.abort() };}// Использованиеconst { promise, cancel } = fetchWithCancel('/api/data');promise.then(data => console.log(data)).catch(err => {if (err.name === 'AbortError') console.log('Запрос отменён');});cancel(); // отменяем запрос// Обёртка для отмены любого промисаfunction makeCancelable(promise) {let rejectFn;const wrapped = new Promise((resolve, reject) => {rejectFn = reject;promise.then(resolve).catch(reject);});return {promise: wrapped,cancel: () => rejectFn(new Error('Promise cancelled'))};}
Как отвечать на собеседовании
Начни с чёткого утверждения: промисы нельзя отменить нативно, но есть обходные пути. Упомяни AbortController как стандартный механизм для fetch и других Web API. Покажи понимание разницы между отменой (прерывание выполнения) и обработкой ошибок (catch). Приведи пример из практики - отмена запроса при размонтировании React-компонента. Упомяни, что в Node.js есть AbortSignal.timeout() для тайм-аутов. Если спросят про Bluebird - скажи, что это легаси-подход, в современном коде предпочтительнее нативные решения.
Что проверяет интервьюер
- Понимание асинхронной модели JavaScript и состояний промиса
- Знание современных Web API (AbortController, AbortSignal)
- Умение проектировать отменяемые асинхронные операции
- Понимание trade-off между отменой и обработкой ошибок
- Опыт работы с реальными кейсами (React, Node.js)
Типичные ошибки
- Утверждение, что
.cancel()существует у промиса - это неверно - Путаница между отменой промиса и остановкой выполнения кода (промис не останавливает выполнение функции)
- Игнорирование обработки ошибки отмены (AbortError) - её нужно ловить отдельно
- Создание утечек памяти: невызванный reject при отмене оставляет промис в pending навсегда
- Использование глобальных флагов отмены вместо изолированных токенов - это приводит к багам при параллельных вызовах
> Похожие задачи по frontend
Что представляет браузер и какие объекты он предоставляет
Что такое среда исполнения JavaScript
Как выполняется цикл с условием сравнения строки и числа в JavaScript?
Как проверить, что первый аргумент является числом в JavaScript?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью