Цикл For-await, требующий времени для получения результата

#reactjs #react-native #async-await #es6-promise #for-await

#reactjs #реагировать-родной #асинхронный-ожидание #es6-обещание #для-ожидание

Вопрос:

Я использую цикл for await для перебора массива и сопоставления значения внутри firestore cloud, но, к сожалению, результат не соответствует ожиданиям; вот мой код

 (async () => {
for await (const element of array) {
firestore().collection('users').where('value', '==', element).get()
.then(async snapshot () => {
setvalue(snapshot.data())
}
setIsLoading(false);
}();
 

Когда я запускаю приложение в эмуляторе, и массив содержит 2 элемента, он просто выдает мне результат, как и ожидалось, но когда массив превышает 40 или n-е число, результат обновляется не так, как ожидалось, и через несколько минут отображается ожидаемый результат.
Я просто хочу обновить состояние isLoading false, когда цикл for await завершит свой цикл, а также код внутри блока цикла завершит проверку firebase, а затем только setIsLoading(false)

Комментарии:

1. Выполнение сетевых запросов внутри цикла — плохая идея. Очень, очень медленно. Пакетируйте его в один запрос.

Ответ №1:

Вместо for await этого используйте await для своей get() функции.
Это должно сработать!

 (async () => {
  for (const element of array) {
    const snapshot = await firestore().collection('users').where('value', '==', element).get();
    setvalue(snapshot.data());
  }
  setIsLoading(false);
}();
 

Ответ №2:

 (async () => {

const allValues = await Promise.all(array.map( item => {

return firestore().collection('users').where('value', '==', element).get()
.then(async snapshot () => {
 //do something

 return value
}

})

console.log('allValues', allValues)
setIsLoading(false);
}();
 

Вы можете рассмотреть возможность использования Promise.all и дождаться завершения всех операций.

Как было рекомендовано ранее, лучше разбить его на куски и вместо этого использовать where(‘value’,’in’, array) .

Обновление — использовать для цикла (я разбиваю их на этапы, чтобы вы могли изменять их для собственного использования)

 //create a function
const myJob = async() => doSomething

//empty array to hold all the async jobs.
let myPromises = []

//for loop to do whatever u want.
for ( var i = 0; i < 10; i  ) {
     myPromises.push(myJob(i));
}

//now call Promise.all with the array of jobs
const myResults = Promise.all(myPromises);
 

Комментарии:

1. Да, но если размер массива превысит 10, это не сработает, я также попробовал с помощью array.slice, но результат тот же

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

3. Чего я пытаюсь достичь, так это того, что существует массив электронных писем из более чем 50, и я хочу просмотреть электронные письма и сопоставить документ пользователей, где email == электронное письмо, которое находится в массиве, и если есть документ, то есть хук useState, который можно обновить, используя previousstateметод и значение добавляются в этом состоянии…

4. разделите их на массивы по 10 и используйте значение where в цикле. Таким образом , вы только звоните . где 5 раз, а не 50 раз. Не имеет значения, является ли это firebase или любой другой базой данных. Вызов API 50 раз подряд означает 50 вызовов базы данных, 50 сетевых накладных расходов и т. Д. С каждым вызовом он становится экспоненциально медленнее.

5. Ценю ваш ответ, я уже пробовал это, но при использовании предложения in я сталкиваюсь с тем, что при наличии 50 электронных писем цикл for выполняется как ожидалось, но код, который устанавливает загрузку (false), срабатывает до того, как все 5 записей находятся в асинхронном запросе…