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