Search code examples
javascriptecmascript-6promisejavascript-objectses6-promise

Values of a promise in JS within for loop


I am lost in the promised land and could really use some guidance. I have exhausted searching numerous SO questions (2-3 hours of reading solutions + docs) related to this seemingly common issue and feel I just am not getting it.

Overview

Below I have code that takes in an Object type (resources), grabs a few values from this Object and then calculates distance and duration from the GoogleMaps Distance Matrix. The results of the function googleRequest() are a promise containing two values (distance and duration).

I would like to get these two values back within the for loop, execute pushToRows(), and then return an array called final_rows.

Problem

final_rows shows UNDEFINED for the duration and distance keys within each row. I speculate this is occurring because I am attempting to access the values in dist_dur inappropriately. I would appreciate any help on resolving this issue. Thanks.

Code

final_rows = []

    function getDistTime(resources){
        for (var i = 0; i < resources.data.length; i++) {
            var origin1 = $("#citystate").val();
            var destinationA = resources.data[i]['DEMOBILIZATION CITY'] + ',' + resources.data[i]['DEMOBILIZATION STATE'];
            var dist_time_data = googleRequest(origin1, destinationA).then((values) => {
                return values
            })
            pushToRows(resources.data[i], dist_time_data)
        }
        // console.log(final_rows)

    } 

    function pushToRows(resources, dist_dur){
        resources["DISTANCE_MI"] = dist_dur[0];
        resources["ACTUAL_DUR_HR"] = dist_dur[1];
        resources["FINANCE_DUR_HR"] = (dist_dur[0] / 45.0).toFixed(2)
        final_rows.push(resources)   
    }

Solution

  • So, what you would need to do is just store promises in an array in the for loop and then wait for these promises to resolve using Promise.all but this would parallelize your requests to google distance api.

        function getDistTime(resources){
            const promiseArr = [];
            for (var i = 0; i < resources.data.length; i++) {
                var origin1 = $("#citystate").val();
                var destinationA = resources.data[i]['DEMOBILIZATION CITY'] + ',' + resources.data[i]['DEMOBILIZATION STATE'];
                promiseArr.push(googleRequest(origin1, destinationA));
                
            }
            // Not sure how would you use the data pushed in rows but since you are not waiting for promises to be resolved, data would be updated later on 
            return Promise.all(promiseArr)
                .then((resultsArr) => {
                    resultsArr.forEach((result, i) => pushToRows(resources.data[i], result));
                })
    
        } 
    
        function pushToRows(resources, dist_dur){
            resources["DISTANCE_MI"] = dist_dur[0];
            resources["ACTUAL_DUR_HR"] = dist_dur[1];
            resources["FINANCE_DUR_HR"] = (dist_dur[0] / 45.0).toFixed(2)
            final_rows.push(resources)   
        }
    

    I would recommend to use async-await which are syntactic sugar to promises but make your code easy to understand and remove the complications that come with promise chaining.