> Как повесить обработчик на резолв каждого промиса в массиве для реализации any? (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Яндекс
Стек: JavaScript
> Пример ответа
Короткий ответ
Для реализации Promise.any не нужно вешать обработчик на резолв каждого промиса в массиве. Достаточно создать массив промисов и передать его в Promise.any. Если нужно отслеживать резолв каждого промиса, можно использовать Promise.allSettled или обернуть каждый промис в дополнительный .then() с колбэком. Но для Promise.any это избыточно - он сам возвращает первый успешно завершённый промис.
Подробное объяснение
Promise.any - это встроенный метод, который принимает итерируемый объект промисов и возвращает один промис, который резолвится значением первого успешно завершённого промиса. Если все промисы отклонены, возвращается AggregateError. Для кастомной реализации Promise.any можно использовать подход с отслеживанием состояния каждого промиса через обработчик на .then(). Это нужно, чтобы определить, какой промис завершился первым успешно, и зарезолвить итоговый промис. Обработчик вешается на каждый промис через .then(value => resolve(value)), где resolve - это функция резолва внешнего промиса. При этом важно обработать отклонения: для каждого промиса добавляется .catch(), который увеличивает счётчик ошибок. Когда счётчик достигает длины массива, внешний промис отклоняется с AggregateError.
На практике
В реальных проектах не нужно писать кастомный Promise.any - используйте встроенный. Но если интервьюер просит реализовать его вручную, важно показать понимание работы с промисами и обработки ошибок. Ключевые моменты: создание внешнего промиса, итерация по массиву, вызов .then() на каждом элементе с вызовом resolve, и .catch() для подсчёта ошибок. Также нужно учесть случай пустого массива - сразу отклонить с AggregateError. Для проверки завершения всех промисов используйте счётчик, а не Promise.all, так как Promise.all отклоняется при первой ошибке.
Пример кода
JAVASCRIPTfunction promiseAny(promises) {return new Promise((resolve, reject) => {if (promises.length === 0) {reject(new AggregateError([], 'All promises were rejected'));return;}let rejectedCount = 0;const errors = new Array(promises.length);promises.forEach((promise, index) => {Promise.resolve(promise).then(value => {resolve(value);}).catch(error => {errors[index] = error;rejectedCount++;if (rejectedCount === promises.length) {reject(new AggregateError(errors, 'All promises were rejected'));}});});});}
Как отвечать на собеседовании
Начни с краткого объяснения, что Promise.any уже есть в стандарте, но если нужно реализовать вручную, то ключевой момент - повесить обработчик на .then() каждого промиса, который вызывает resolve внешнего промиса. Подчеркни, что обработчик должен быть именно на резолв, а не на reject. Объясни, как обрабатываются ошибки через счётчик и AggregateError. Упомяни edge cases: пустой массив, не-промис значения (используй Promise.resolve), и что метод должен работать с любым итерируемым объектом. Не углубляйся в микрооптимизации, пока не спросят.
Что проверяет интервьюер
Интервьюер проверяет понимание работы промисов, умение создавать кастомные асинхронные утилиты, знание AggregateError и обработку ошибок. Также оценивается способность рассмотреть edge cases и написать чистый, рабочий код без лишних зависимостей. Важно показать, что ты понимаешь разницу между Promise.any, Promise.race, Promise.all и Promise.allSettled.
Типичные ошибки
- Использование
Promise.allдля отслеживания завершения всех промисов - он отклоняется при первой ошибке, что не подходит дляPromise.any. - Забывание обернуть не-промис значения в
Promise.resolve. - Неправильная обработка пустого массива - нужно сразу отклонить промис.
- Использование
rejectвместоresolveпри первом успешном завершении. - Неучёт того, что
AggregateErrorдолжен содержать массив ошибок в том же порядке, что и исходные промисы.
> Похожие задачи по frontend
Что такое проваливание промисов (Promise rejection) в JavaScript
Что произойдет при прямой мутации состояния в редьюсере Redux
Почему нельзя просто вернуть Promise.resolve с промисом внутри в реализации any?
Как определить момент завершения всех промисов с ошибками для вызова reject в JavaScript?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью