Задача
Реализуйте функцию allSettled(iterable), которая работает аналогично Promise.allSettled():
- Принимает массив (или итерируемый объект) промисов и/или обычных значений;
- Возвращает промис, который всегда разрешается (никогда не отклоняется);
- Результат — массив объектов с полями:
{ status: "fulfilled", value: ... }для успешных промисов;{ status: "rejected", reason: ... }для отклонённых промисов.
- Порядок результатов соответствует порядку входных элементов;
- Не используйте встроенный
Promise.allSettledв реализации.
Пример
// Тест 1: смешанные успешные и отклонённые промисы
allSettled([
Promise.resolve(42),
Promise.reject(new Error("oops")),
Promise.resolve("hello"),
]).then(console.log);
// [
// { status: "fulfilled", value: 42 },
// { status: "rejected", reason: Error("oops") },
// { status: "fulfilled", value: "hello" }
// ]
// Тест 2: обычные значения (не промисы)
allSettled([1, 2, 3]).then(console.log);
// [
// { status: "fulfilled", value: 1 },
// { status: "fulfilled", value: 2 },
// { status: "fulfilled", value: 3 }
// ]
// Тест 3: пустой массив
allSettled([]).then(console.log); // []
// Тест 4: все промисы отклонены
allSettled([
Promise.reject("error1"),
Promise.reject("error2"),
]).then(console.log);
// [
// { status: "rejected", reason: "error1" },
// { status: "rejected", reason: "error2" }
// ]Решение
Оптимальное решение
function allSettled(promises) { if (!promises.length) return Promise.resolve([]); const result = []; let completedCount = 0; return new Promise((resolve) => { promises.forEach((promise, index) => { Promise.resolve(promise) .then((value) => { result[index] = { status: "fulfilled", value }; }) .catch((err) => { result[index] = { status: "rejected", reason: err }; }) .finally(() => { completedCount++; if (completedCount === promises.length) { resolve(result); } }); }); }); }
Альтернативное решение (через Promise.all)
function allSettled(promises) { return Promise.all( promises.map((promise) => Promise.resolve(promise) .then((value) => ({ status: "fulfilled", value })) .catch((reason) => ({ status: "rejected", reason })) ) ); }