-2

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)   
    }
jclark754
  • 914
  • 2
  • 12
  • 30

2 Answers2

1

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.

Ravi Chaudhary
  • 660
  • 6
  • 22
  • `i` is undefined in your `forEach` loop. You should not use `final_rows.push` at all, rather make a promise for the `resources` and have the `final_rows` as the result of the `Promise.all` – Bergi Jul 14 '20 at 18:49
  • true. my bad. also, we could use index from forEach since ordering would be maintained to update – Ravi Chaudhary Jul 14 '20 at 18:51
  • One could use the index from `forEach`, but one should not use `forEach` at all. – Bergi Jul 14 '20 at 18:52
0

If you move your pushToRows() inside where you return values, you will have access to that data.

googleRequest(origin1, destinationA).then((values) => {
    pushToRows(resources.data[i], values);
});

Until that promise resolves, dist_time_data would be undefined

You could also convert to Promise.all() which takes an array of promises and resolves when all of the promises are complete:

function getDistTime(resources){
    const promises = [];

    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'];
        promises.push(googleRequest(origin1, destinationA));
    }

    return Promise.all(promises).then((results) => {
        return results.map((result, i) => {
            return {
                ...resources.data[i],
                DISTANCE_MI: result[0],
                ACTUAL_DUR_HR: result[1],
                FINANCE_DUR_HR: (result[0] / 45.0).toFixed(2)
            };
        });
    });
}

getDistTime(resources).then(result => {
    //result is now "final_rows"
});
Anthony
  • 6,422
  • 2
  • 17
  • 34