Я знаю, что promise.all() терпит неудачу, когда даже одно обещание не выполняется. Я только хочу попытаться выполнить невыполненные обещания и не хочу снова запускать promise.all().
Какие-либо рекомендации о том, как я могу достичь этого минимальным способом?
Да, упаковка результатов внутри { success: bool, value: any } - это хорошо, но вы также должны предоставить функцию retry для невыполненных обещаний.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Обещания стремятся конструировать и моделировать значение, полученное асинхронно,
Promise создается с использованием какого-либо производителя, например fetch.
Если вы сохраните ссылку на этого производителя, вы можете воспроизвести механизм это в первую очередь произвело Обещание.
// producer function
function getData (arg) {
const result = new Promise();
return result.then(value => {
return { ok:true, value };
}, error => {
return {
ok: false,
value: error,
// retry is a function which calls the producer with the same arguments
retry: () => getData(arg)
};
})
}
Тогда, если у вас есть что-то вроде:
const data = [];
// Promise<{ok: boolean, value: any, retry?: function}>
// No promises will fail in this array
const asyncResults = data.map(getResults);
Promise.all(asyncResults)
.then((results) => {
const successes = results.filter(res => res.ok);
const retrys = results.filter(res => !res.ok).map(res => res.retry()); // retry all failed promises
})
Утечки памяти, переполнение стека: поскольку я сохраняю ссылку на исходные аргументы, чтобы повторить попытку, а алгоритм является рекурсивным, возможна утечка памяти. Однако алгоритм не может «переполнить стек»:
getData со временем не становятся «глубже» (см. Определение retry)const resultData = results.filter(res => res.ok).map(res => res.value);Однако алгоритм может занять много времени, если обещание не будет разрешено и будет препятствовать доступу к остальным значениям.
В качестве альтернативы я предлагаю вам взглянуть на другой асинхронный примитив, еще не являющийся частью языка (возможно, когда-нибудь): Observables, который предназначен для такого рода задач: ленивые асинхронные операции с возможностью повторения.
Я не упомянул об этом в ответе, но вся эта структура рекурсивна. retrys - это массив обещаний, который необходимо объединить со значениями успеха.
так как это рекурсивно, есть ли шанс, что стековая память закончится?
Я обновил для вас комментарий. В моем ответе отсутствует конец алгоритма, оставленный в качестве упражнения (на самом деле, несколько способов справиться с этим в зависимости от вашего варианта использования и данных). У вас есть еще вопросы?
нет, это не решает мою сценарную проблему. Но было хорошо научиться
Вы можете использовать асинхронный пакет и заключить все вызовы обещаний закрытием с аргументом done.
Затем просто разрешите результаты.
const async = require('async');
const promiseAll = promises => {
return new Promise((resolve) => {
const parallelCalls = promises.map(promise => {
return done => {
promise
.then(result => done(null, result)
.catch(error => {
console.error(error.message);
done();
});
}
});
async.parallel(
parallelCalls,
(_, results) => resolve(results.filter(result => result))
);
});
};
router.get('/something', async (req, res) => {
...
const results = await promiseAll(promises);
...
});
один простой трюк - обернуть каждое обещание (возвращает успех или неудачу) другим обещанием (которое всегда возвращает успех). затем подсчитайте неудачи и успехи с помощью обещания.all ().