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

时间:2019-02-21 13:32:51

标签: javascript reactjs async-await

我在React中有这段代码,该代码调用Dark Sky API,并返回特定日期的天气数据。每个请求都有一个特定的日期。一旦请求成功,我将通过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 :(得分:2)

您可以使用..其中将按顺序运行:

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

答案 1 :(得分:2)

使用Promise.all。比所有循环中使用递归或等待更快,因为所有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
});

答案 2 :(得分:1)

问题在于,没有什么可以确保一个请求先于另一个请求完成,但这取决于如何实现函数darkSky。据我从您的代码中猜测,它看起来像这样:

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

因为您使用onTimeRequestSuccess来解决darkSky内部的承诺,所以processArray中的await不会等待获取承诺,而是会等待onTimeRequestSuccess的结果。这就是为什么不保留订单的原因。

如果要保持顺序(获取数据后不重新排序)并且不具有连续30次调用的链,则一种方法可以是创建一个具有所有查询的诺言的数组,等待使用来解决所有问题Promise.all,然后将整个数组设置为state。例如:

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

答案 3 :(得分:0)

您可以尝试递归函数调用。像这样的东西:

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)  
但是,正如评论中提到的那样,调用全部然后进行排序会更快。