> Реализовать функцию, принимающую массив промисов и возвращающую массив результатов или первый reject в JavaScript (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: IT-One
Стек: JavaScript
> Пример ответа
Короткий ответ
Реализация promiseAll сводится к созданию массива результатов с сохранением порядка, параллельному запуску всех промисов и reject при первой ошибке. Для этого используем Promise.all или пишем свою версию через then и catch, отслеживая количество завершённых промисов. Важно обрабатывать пустой массив и не-промис значения.
Подробное объяснение
Функция promiseAll принимает iterable промисов и возвращает новый Promise. Основные требования:
- Сохраняет порядок результатов согласно исходному массиву
- Возвращает массив результатов при успешном завершении всех промисов
- Отклоняет результат при первом же reject с ошибкой этого промиса
- Работает с пустым массивом (возвращает resolved с пустым массивом)
- Обрабатывает не-промис значения (оборачивает их в
Promise.resolve)
Реализация использует счётчик завершённых промисов и массив результатов с индексами. Каждый промис при resolve сохраняет результат в соответствующую позицию и увеличивает счётчик. Когда счётчик равен длине массива - resolve с результатами. При любом reject - сразу reject с ошибкой.
На практике
В реальных проектах используют встроенный Promise.all, но понимание его реализации важно для:
- Отладки асинхронного кода
- Создания кастомных вариаций (например, с таймаутом или retry)
- Работы в окружениях без поддержки современных API
- Оптимизации под специфичные сценарии (например, лимит параллельных запросов)
Пример кода
JAVASCRIPTfunction promiseAll(promises) {return new Promise((resolve, reject) => {if (!promises || typeof promises[Symbol.iterator] !== 'function') {reject(new TypeError('Argument must be iterable'));return;}const arr = Array.from(promises);if (arr.length === 0) {resolve([]);return;}const results = new Array(arr.length);let completed = 0;arr.forEach((item, index) => {Promise.resolve(item).then((value) => {results[index] = value;completed++;if (completed === arr.length) {resolve(results);}},(error) => {reject(error);});});});}
Как отвечать на собеседовании
Начни с описания сигнатуры и поведения функции. Объясни ключевые моменты: сохранение порядка, параллельное выполнение, обработка ошибок. Покажи реализацию и прокомментируй важные детали: использование Promise.resolve для не-промисов, проверку на iterable, работу с пустым массивом. Обсуди trade-off: почему нельзя использовать forEach с async/await (последовательное выполнение) и как избежать race condition при записи результатов.
Что проверяет интервьюер
- Понимание асинхронности и промисов
- Умение работать с коллбеками и замыканиями
- Внимание к edge cases (пустой массив, не-промис значения, ошибки)
- Способность реализовать параллельное выполнение без гонок данных
- Знание встроенных методов Promise и их отличий
Типичные ошибки
- Использование
forEachсasync/await- приводит к последовательному выполнению - Неправильная обработка пустого массива (возврат pending промиса)
- Отсутствие обёртки не-промисов через
Promise.resolve - Использование
results.push()вместо индексов - нарушает порядок - Необработка случая, когда передан не iterable объект
- Утечка памяти при большом количестве промисов (не критично для собеседования)
> Похожие задачи по frontend
Что такое Redux, зачем он нужен и как устроен
Как решать задачу анимации шаг за шагом
Как реализовать мемоизацию функции в JavaScript
Как реализовать функцию retry для повторного вызова асинхронной функции при ошибке в JavaScript
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью