Search code examples
javascriptasync-awaitfetches6-promise

How do I wait for one fetch to be finished before starting another fetch when using a for loop?


I am looping through an array containing a number of objects and for each object I want to make a fetch which should return a time prediction based on information about the current object. I then want to add this time to a time variable that is declared outside the loop. In the example below I have two objects in the array. The first object returns a time of 34 and the second object returns a time of 72. However, when I check the time it is always only 72. Because of this I think the first might not be completing before the second one starts. The code looks as follows:

for (var l = 0; l < journeyArr.length; l++){
                        console.log("time at start of loop: ", time)
                        startStop = journeyArr[l].stops[0].id
                        endStop = journeyArr[l].stops[journeyArr[l].stops.length - 1].id 
                        routeid = journeyArr[l].routeid
                        lineid = journeyArr[l].lineid
                        fetch("http://localhost:8000/routes/api/predict/?lineid="+lineid+"&start_stop="+startStop+"&end_stop="+endStop+"&routeid="+routeid+"&time_secs="+seconds+"&temp="+temp+"&rain=0.16&dow="+dayNum)
                        .then(response => {
                            return response.json()
                        })
                        .then(data => {
                            time += data.journey_info.journey_time.hours * 60
                            time += data.journey_info.journey_time.minutes
                        })
                    }
                    //Timeout just after the for loop to fetch times and to calculate
                    setTimeout(()=>{
                        var hours = Math.floor(time / 60);  
                        var minutes = time % 60;
                        timeLeft.innerHTML = hours + " hour(s) " + minutes + " minutes";
                     },10000)

Solution

  • You can use async/await in this case. Put your code inside an async function, and trigger fetch by calling the function.

    let fetchData = async () => {
        let time = 0;
        for (var l = 0; l < journeyArr.length; l++){
            console.log("time at start of loop: ", time)
            startStop = journeyArr[l].stops[0].id
            endStop = journeyArr[l].stops[journeyArr[l].stops.length - 1].id 
            routeid = journeyArr[l].routeid
            lineid = journeyArr[l].lineid
            const response =  await fetch("http://localhost:8000/routes/api/predict/?lineid="+lineid+"&start_stop="+startStop+"&end_stop="+endStop+"&routeid="+routeid+"&time_secs="+seconds+"&temp="+temp+"&rain=0.16&dow="+dayNum)
            const data = response.json()
            time += data.journey_info.journey_time.hours * 60
            time += data.journey_info.journey_time.minutes
        }
        //Timeout just after the for loop to fetch times and to calculate
        setTimeout(()=>{
            var hours = Math.floor(time / 60);  
            var minutes = time % 60;
            timeLeft.innerHTML = hours + " hour(s) " + minutes + " minutes";
        },10000)
    }
    
    fetchData() // Trigger the fetch loop