简体   繁体   English

javascript 中的异步/等待 for 循环

[英]Async/Await in javascript for loop

I have a react component that runs this function on the mounting of the component.我有一个反应组件,它在组件的安装上运行这个 function。

 function getListOfItems(){
    let result = [];
    for(let i=0 ; i<5 ; i++){
        /**
         * code to assign values to some variables namely param1,param2
         */
        getDetails(param1,param2);
    }
    const getDetails = async (param1,param2) => {
        let list = await getAPIresults(param1)
        result.push(list);
        if(result.length === 5){
            //code to update a hook which causes render and displays the text in results array
        }
    }
 }
  
 useEffect(() => {
   getListOfItems()
 },[])

So the code is running but the results array has data in random order.所以代码正在运行,但结果数组的数据是随机顺序的。 For instance, the results array might look something like this [2,5,1,3,4] where I expect it to be like this [1,2,3,4,5] This means the above code is not running async tasks in the order of their arrival.例如,结果数组可能看起来像这样[2,5,1,3,4]我希望它像这样[1,2,3,4,5]这意味着上面的代码没有运行异步任务按他们到达的顺序。 So could someone help me out to fix this, I want the code to make async requests in order of their arrival.所以有人可以帮我解决这个问题,我希望代码按照到达的顺序发出异步请求。

You need to use the await keyword again to wait for each iteration of the loop to complete before it moves on to the next go-round.您需要再次使用await关键字来等待循环的每次迭代完成,然后再进入下一轮。

await getDetails(param1,param2)

But as you can only do this in an async function, your getListOfItems will also need to be an async function.但是由于您只能在异步 function 中执行此操作,因此您的getListOfItems也需要是异步 function。

async function getListOfItems(){
    let result = [];
    for(let i=0 ; i<5 ; i++){
        await getDetails(param1,param2);
    }
    const getDetails = async (param1,param2) => {
        let list = await getAPIresults(param1)
        result.push(list);
        if(result.length === 5){}
    }
 }

So the code is running but the results array has data in random order.所以代码正在运行,但结果数组的数据是随机顺序的。

That's because your loop calls getDetails repeatedly without waiting for the previous call to complete.那是因为您的循环重复调用getDetails而不等待前一个调用完成。 So all the calls overlap and race.所以所有的电话都重叠和竞争。

If it's okay that they overlap but you need the results in order, use Promise.all and have getDetails return its results (rather than pushing them directly).如果它们可以重叠,但您需要按顺序排列结果,请使用Promise.all并让getDetails返回其结果(而不是直接推送它们)。

If you can't make getListOfItems an async function:如果您不能getListOfItems async function:

const getDetails = async (param1,param2) => {
    let list = await getAPIresults(param1)
    if(result.length === 5){
        //code to update a hook which causes render and displays the text in results array
    }
    return list;
}
const promises = [];
for (let i = 0; i < 5; ++i) {
    promises.push(getDetails(param1, param2));
}
Promise.all(promises)
.then(results => {
    // `results` is an array of the results, in the same order as the
    // array of promises
})
.catch(error => {
    // Handle/report error
});

If you can (and the caller will handle any error that's propagated to it via rejection of the promise from getListOfItems ):如果可以(并且调用者将通过从getListOfItems拒绝 promise 来处理传播给它的任何错误):

const getDetails = async (param1,param2) => {
    let list = await getAPIresults(param1)
    if(result.length === 5){
        //code to update a hook which causes render and displays the text in results array
    }
    return list;
}
const promises = [];
for (let i = 0; i < 5; ++i) {
    promises.push(getDetails(param1, param2));
}
const results = await Promise.all(promises)
// `results` is an array of the results, in the same order as the
// array of promises

If you need them not to overlap but instead to run one after another, your best bet is to use an async function for the loop.如果您需要它们不重叠而是一个接一个地运行,最好的办法是使用async function 进行循环。

If you can't make getListOfItems an async function:如果您不能getListOfItems async function:

const getAllResults = async function() {
    const results = [];
    for (let i = 0; i < 5; ++i) {
        results.push(await getDetails(param1, param2));
    }
    return results;
}
const getDetails = async (param1,param2) => {
    let list = await getAPIresults(param1)
    if(result.length === 5){
        //code to update a hook which causes render and displays the text in results array
    }
    return list;
}
getAllResults()
.then(results => {
    // `results` is an array of the results, in order
})
.catch(error => {
    // Handle/report error
});

If you can (and the caller will handle any error that's propagated to it via rejection of the promise from getListOfItems ):如果可以(并且调用者将通过从getListOfItems拒绝 promise 来处理传播给它的任何错误):

const results = [];
for (let i = 0; i < 5; ++i) {
    results.push(await getDetails(param1, param2));
}
// Use `results
const getDetails = async (param1,param2) => {
    let list = await getAPIresults(param1)
    if(result.length === 5){
        //code to update a hook which causes render and displays the text in results array
    }
    return list;
}

You might want to use Promise.all ;您可能想使用Promise.all this would preserve the order as well:这也将保留订单:

Promise.all: Order of resolved values Promise.all:解析值的顺序

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

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