Promise.all и построение запросов axios внутри асинхронной функции

Я зацикливаю данные для создания нескольких запросов 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 разрешается до того, как один из запросов завершится (ошибки и перейдет к отлову)?

Итак, ваш вопрос: «Почему Promise.all разрешается до того, как catch срабатывает внутри цикла forEach»? Каково ваше желаемое поведение?

codemonkey 15.12.2020 04:33

@codemonkey Извините, да. сделал это более ясным в моем вопросе.

crimson589 15.12.2020 04:37

Вам интересно только узнать, почему, или вы действительно пытаетесь найти способ отлавливать ошибки до того, как Promise.all разрешится? Мне нечего предложить в отношении первого, но если дело во втором, я могу предложить несколько изменений, которые заставят ваш код вести себя разумно.

codemonkey 15.12.2020 04:45

Это может помочь опубликовать вывод, который вы получаете, включив операторы консоли в свои функции выше, но не уверен, что полностью понимаю проблему.

cppNoob 15.12.2020 04:49

@codemonkey последнее было бы очень полезно, спасибо.

crimson589 15.12.2020 04:49

Итак, чтобы быть уверенным, если один или несколько запросов axios перехватят, вы не хотите, чтобы это обещание было помещено в ваш массив requestArr? Или вы хотите, чтобы вся функция бомбила? Как именно вы хотите, чтобы код вел себя?

codemonkey 15.12.2020 05:04

@codemonkey Я хочу, чтобы его отправили. Я хочу отправить каждый запрос в requestArr, и Promise.all должен разрешаться только после завершения всех запросов (успешно или с ошибкой)

crimson589 15.12.2020 05:09
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
7
5 495
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Из того, что я вижу, вы отправляете обещания в requestArr асинхронно, поэтому, если вы вызовете promise.all массив до его заполнения. Это будет разрешено, когда обещания в нем разрешатся. Удалив await, вы быстро переместите все запросы в requestArr.

Итак, чтобы ответить на ваш вопрос, он разрешается, потому что все запросы в requestArr были разрешены до того, как requestArr.push() был вызван для вашего обещания об ошибке.

Вы можете попробовать использовать свою собственную функцию asyncforeach, чтобы сделать это лучше.

async function asyncForEach(array, callback) {
  for (let index = 0; index < array.length; index++) {
    await callback(array[index], index, array);
  }
}

Теперь вы можете awaitforeach перед вызовом 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 выполняется.

crimson589 15.12.2020 04:57
Ответ принят как подходящий

Это заставит ваш 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 15.12.2020 06:31

@crimson589 Отличный вопрос. Promise.all в вашем коде фактически пытается разрешить пустой массив. Это достигается до того, как ваш цикл forEach сможет что-либо поместить в переменную requestArr. Неудивительно, что он разрешается до того, как любой из ваших вызовов axios. Напротив, map заполняет requestArr тем, что возвращается из его функции (обещаниями в нашем случае), прежде чем перейти к следующей строке. Вот в чем разница. На это, кстати, указывает и Тодд Скелтон в своем ответе.

codemonkey 15.12.2020 07:02

Другие вопросы по теме