简体   繁体   English

React中for循环内部的异步函数

[英]Async function inside for loop in React

I have this piece of code in React which calls the Dark Sky API and returns weather data for a specific day. 我在React中有这段代码,该代码调用Dark Sky API,并返回特定日期的天气数据。 Each request gets a particular date. 每个请求都有一个特定的日期。 Once the request is successful, I put the data in an array via setState. 一旦请求成功,我将通过setState将数据放入数组中。 The code runs fine but each request runs asynchronously so the data gets pushed to the array in the order in which each call completes so it's not getting me an ordered day list. 代码运行良好,但是每个请求都是异步运行的,因此,数据将按照每个调用完成的顺序推送到数组中,因此不会得到我的订购日列表。 Here's the code: 这是代码:

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);
  }
}

Thanks! 谢谢!

You can use for.. of which will run in sequence: 您可以使用for ..将按顺序运行:

async function processArray(array) {
  for (const item of array) {
    await darkSky(url, this.onTimeRequestSuccess, this.onError);
  }
 console.log('Done!');
}

Use Promise.all . 使用Promise.all Waaay faster than using recursion or await in a loop, as all the API calls will happen concurrently rather than sequentially. 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
});

The problem is that nothing ensures you one request finish before another, but it depends on how the function darkSky it's implemented. 问题是,没有什么可以确保一个请求先于另一个请求完成,但这取决于如何实现darkSky函数。 As far as I can guess from your code it will look something like this: 据我从您的代码中猜测,它看起来像这样:

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

Because you're using onTimeRequestSuccess as a resolving on the promise inside darkSky the await in processArray is not going to wait for the fetch promise, instead is going to wait for the result of onTimeRequestSuccess . 因为您使用onTimeRequestSuccess来解决darkSky所以processArray的await不会等待获取onTimeRequestSuccess ,而是会等待onTimeRequestSuccess的结果。 That's why the order is not maintained. 这就是为什么不维护订单的原因。

If you want to keep the order (without reordering after getting the data) and not having a chain of 30 consecutive calls, one approach could be create an array with the promises of all the queries, wait for all to be resolved using Promise.all and then setting the whole array to the state. 如果要保持顺序(获取数据后不重新排序)并且不具有连续30次调用的链,则一种方法是创建一个具有所有查询承诺的数组,等待使用Promise.all解决所有问题然后将整个数组设置为state。 Eg: 例如:

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}));
}

You could try recurssive function call. 您可以尝试递归函数调用。 something like this: 像这样的东西:

 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) 
But as mentioned in comments, calling all and then sorting will be faster. 但是,正如评论中提到的那样,调用全部然后进行排序将更快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM