Реализовать функцию, принимающую массив промисов и возвращающую массив результатов или первый reject в JavaScript
Что проверяют
Знаете ли вы семантику Promise.all и сможете ли повторить её руками. Вопрос так и формулируют, чтобы вы не отделались вызовом готового метода, а показали работу со счётчиком, с порядком результатов и с однократным разрешением промиса.
Как отвечать
Скажите сразу, что описанное поведение это ровно Promise.all: массив результатов в порядке входа, отказ при первом же отклонении. Потом напишите свою версию:
function all(items) {
const list = [...items];
return new Promise((resolve, reject) => {
const values = new Array(list.length);
let pending = list.length;
if (pending === 0) resolve(values);
list.forEach((item, i) => {
Promise.resolve(item).then((value) => {
values[i] = value;
if (--pending === 0) resolve(values);
}, reject);
});
});
}Проговорите ключевые места. Значение кладётся по своему индексу, а не через push, иначе порядок станет порядком завершения. Счётчик уменьшается в каждом успешном колбэке, и только его обнуление разрешает общий промис. Вход оборачивается через Promise.resolve, потому что там могут оказаться обычные значения. Пустой массив разрешается сразу. Повторные вызовы reject безопасны, промис фиксируется один раз.
Отдельно назовите соседей: allSettled дожидается всех и никогда не отклоняется, race отдаёт первый завершившийся любым исходом, any первый успешный. И упомяните, что при отказе остальные промисы не отменяются, они продолжают работу.
Где спотыкаются
Реализуют через allSettled и бросают первую найденную ошибку. Поведение другое: такая версия ждёт завершения всех промисов, а Promise.all отклоняется немедленно, и на медленном запросе разница видна как лишние секунды ожидания.
Второе: считают первым отказом первый по индексу. Первым должен быть первый по времени, на реальных сетевых запросах это разные вещи, и поиск по массиву результатов вернёт не ту ошибку.
Третье: накапливают результаты через push в колбэке. Порядок получается произвольным, но тест на мгновенных локальных промисах этого не показывает, потому что они завершаются в порядке создания.