Я зацикливаю данные для создания нескольких запросов axios, и в этом асинхронном цикле есть ожидание некоторых данных.
Когда я это делаю, Promise.all
разрешается до того, как в одном из запросов возникнет ошибка .catch(errror => {})
Я намеренно дал одни неверные данные, чтобы запрос пошел на перехват.
return new Promise((resolve) => {
let requestArr = [];
requestsData.forEach(async (data) => {
let waitForThisData = await someFunction(data.id);
requestArr.push(
axios
.post()
.then((response) => {})
.catch((error) => {})
);
});
Promise.all(requestArr).then(() => {
resolve(true);
});
});
Я тестирую это с 3 запросами, 1 из которых будет пойман. Когда я добавил точки останова, Promise.all
уже разрешается перед переходом к одному из запросов catch.
Если я удалю код ожидания, я получу ожидаемый результат, сначала поймать триггеры, прежде чем разрешится Promise.all
.
Так почему же Promise.all разрешается до того, как один из запросов завершится (ошибки и перейдет к отлову)?
@codemonkey Извините, да. сделал это более ясным в моем вопросе.
Вам интересно только узнать, почему, или вы действительно пытаетесь найти способ отлавливать ошибки до того, как Promise.all
разрешится? Мне нечего предложить в отношении первого, но если дело во втором, я могу предложить несколько изменений, которые заставят ваш код вести себя разумно.
Это может помочь опубликовать вывод, который вы получаете, включив операторы консоли в свои функции выше, но не уверен, что полностью понимаю проблему.
@codemonkey последнее было бы очень полезно, спасибо.
Итак, чтобы быть уверенным, если один или несколько запросов axios перехватят, вы не хотите, чтобы это обещание было помещено в ваш массив requestArr
? Или вы хотите, чтобы вся функция бомбила? Как именно вы хотите, чтобы код вел себя?
@codemonkey Я хочу, чтобы его отправили. Я хочу отправить каждый запрос в requestArr, и Promise.all
должен разрешаться только после завершения всех запросов (успешно или с ошибкой)
Из того, что я вижу, вы отправляете обещания в requestArr
асинхронно, поэтому, если вы вызовете promise.all
массив до его заполнения. Это будет разрешено, когда обещания в нем разрешатся. Удалив await
, вы быстро переместите все запросы в requestArr
.
Итак, чтобы ответить на ваш вопрос, он разрешается, потому что все запросы в requestArr
были разрешены до того, как requestArr.push()
был вызван для вашего обещания об ошибке.
Вы можете попробовать использовать свою собственную функцию async
foreach
, чтобы сделать это лучше.
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
Теперь вы можете await
foreach
перед вызовом Promise.all()
.
let requestArr = [];
await asyncForEach(requestsData, async (data) => {
let waitForThisData = await someFunction(data.id);
requestArr.push(
axios
.post()
.then((response) => { })
.catch((error) => { })
);
});
Promise.all(requestArr).then(() => {
resolve(true);
});
Я вижу, после просмотра моего кода я вижу это сейчас. Есть часть, которую я не включил в свой пример выше, на самом деле есть некоторая проверка перед оператором ожидания. Не все в цикле будет проходить через оператор ожидания, поэтому код прошел через все в цикле, но один из них все еще «ожидает» и еще не был передан в requestArr
, когда Promise.all
выполняется.
Это заставит ваш Promise.all
разрешить ПОСЛЕ улова внутри цикла, или, действительно, после всех запросов (успешных или неудачных):
const axios = require('axios');
const someFunction = () => {
return new Promise(resolve => {
setTimeout(() => resolve('222'), 100)
})
}
const requestsData = ['https://httpstat.us/200', 'https://httpstat.us/205', 'https://httpstat.us/306']
const requestArr = requestsData.map(async data => {
let waitForThisData = await someFunction(data);
return axios.post(data)
.then(response => {})
.catch(error => console.info(error.toString()))
});
Promise.all(requestArr).then(() => {
console.info('resolved promise.all')
})
https://httpstat.us/306
вызовет ошибочный вызов. Вы можете попробовать разместить его в любом месте массива requestsData
.
Спасибо, это сработало. Но единственная разница, которую я вижу, это то, что теперь используется карта, как это повлияло?
@crimson589 Отличный вопрос. Promise.all
в вашем коде фактически пытается разрешить пустой массив. Это достигается до того, как ваш цикл forEach
сможет что-либо поместить в переменную requestArr
. Неудивительно, что он разрешается до того, как любой из ваших вызовов axios. Напротив, map
заполняет requestArr
тем, что возвращается из его функции (обещаниями в нашем случае), прежде чем перейти к следующей строке. Вот в чем разница. На это, кстати, указывает и Тодд Скелтон в своем ответе.
Итак, ваш вопрос: «Почему
Promise.all
разрешается до того, какcatch
срабатывает внутри циклаforEach
»? Каково ваше желаемое поведение?