Асинхронная функция внутри цикла for в React - PullRequest
0 голосов
/ 21 февраля 2019

У меня есть этот фрагмент кода в React, который вызывает API Dark Sky и возвращает данные о погоде за определенный день.Каждый запрос получает определенную дату.После успешного выполнения запроса я помещаю данные в массив с помощью setState.Код работает нормально, но каждый запрос выполняется асинхронно, поэтому данные передаются в массив в порядке, в котором каждый вызов завершается, поэтому мне не удается получить список упорядоченных дней.Вот код:

loadPreviousMonth = async () => {
  const current = {...this.state};

  for (let i=30; i >= 1; i--) {
    const date = new Date();
    const previousDay = Math.floor(date.setDate(date.getDate() - i) / 1000);
    const url = `/api/darksky?latitude=${current.latitude}&longitude=${current.longitude},${previousDay}`;
    await darkSky(url, this.onTimeRequestSuccess, this.onError);
  }
}

Спасибо!

Ответы [ 4 ]

0 голосов
/ 21 февраля 2019

Проблема в том, что ничто не гарантирует вам выполнение одного запроса перед другим, но это зависит от того, как реализована функция darkSky.Насколько я могу догадаться из вашего кода, он будет выглядеть примерно так:

function darkSky(url, onTimeRequestSuccess, onError) {
     return fecth(url).then(onTimeRequestSuccess).catch(onError);
}

Поскольку вы используете onTimeRequestSuccess в качестве решения для обещания внутри darkSky, ожидание в processArrayне будет ждать обещания получения, вместо этого будет ждать результата onTimeRequestSuccess.Вот почему порядок не поддерживается.

Если вы хотите сохранить порядок (без переупорядочения после получения данных) и не иметь цепочку из 30 последовательных вызовов, одним из подходов может быть создание массива с обещаниямивсе запросы, дождитесь разрешения всех с помощью Promise.all и затем установите весь массив в состояние.Например:

loadPreviousMonth = () => {
  const current = {...this.state};
  const promises = [];

  for (let i=30; i >= 1; i--) {
    const date = new Date();
    const previousDay = Math.floor(date.setDate(date.getDate() - i) / 1000);
    const url = `/api/darksky?latitude=${current.latitude}&longitude=${current.longitude},${previousDay}`;
    promises.push(fetch(url));
  }

  Promise.all(promises).then((results) => this.setState({results: results}));
}
0 голосов
/ 21 февраля 2019

Вы можете попробовать рекурсивный вызов функции.как то так:

var delay = ms => new Promise(res => setTimeout(res, ms));



    function executeInOrder(iteration){
        if(iteration>0){
            delay(500).then(()=>{
                console.log(iteration)
                executeInOrder(iteration-1)
            })
        }
    }
    
  executeInOrder(30)  
Но, как уже упоминалось в комментариях, вызов всех и сортировка будет быстрее.
0 голосов
/ 21 февраля 2019

Использование Promise.all .Waaay быстрее, чем использование рекурсии или ожидание в цикле, так как все вызовы API будут происходить одновременно, а не последовательно.

const promises = [];

for (let i=30; i >= 1; i--) {
    const date = new Date();
    const previousDay = Math.floor(date.setDate(date.getDate() - i) / 1000);
    const url = `/api/darksky?latitude=${current.latitude}&longitude=${current.longitude},${previousDay}`;
    promises.push(darkSky(url, this.onTimeRequestSuccess, this.onError));
}

Promise.all(promises).then(arrOfResults => {
  // setState here
});
0 голосов
/ 21 февраля 2019

Вы можете использовать для .. которого будет работать в последовательности:

async function processArray(array) {
  for (const item of array) {
    await darkSky(url, this.onTimeRequestSuccess, this.onError);
  }
 console.log('Done!');
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...