0

Trying to batch Google ElevationService's requests (and leaving a trail of questions on Stack Overflow) I'm now pointed towards Promise objects, which are completely new to me.

Say I have a loop that runs 4 times, or in another case 7 times, or in yet another case 2 times; how would I implement the Promise aproach in that loop? At this moment this is my set up to try to get elevation data batched in 250 LatLng's a time for a given Google Maps DirectionsResponse.

var currentBatch = 0;
while(currentBatch < totalElevationBatches) {
    getRouteElevationChartDataBatch(currentBatch, batchSize);
    currentBatch++;
}

function getRouteElevationChartDataBatch(batch, batchSize) {
    return new Promise(function(resolve, reject) {
        var elevator = new google.maps.ElevationService();
        var thisBatchPath = [];

        for (var j = batch * batchSize; j < batch * batchSize + batchSize; j++) {
            if (j < directions.routes[0].overview_path.length) {
                thisBatchPath.push(directions.routes[0].overview_path[j]);
            } else {
                break;
            }
        }

        elevator.getElevationAlongPath({
            path: thisBatchPath,
            samples: 256
        }, function (elevations, status) {
            if (status != google.maps.ElevationStatus.OK) {
                reject(status);
            }

            routeElevations = routeElevations.concat(elevations);
        });
    });
}

But these calls are still executed asynchronously because they aren't chained with .then() method. How can I chain a variable number of chains and know when it's done? Sorry if this is a total stupid question; but I don't get it after consulting the documentation (here and here)

Ben Fransen
  • 10,884
  • 18
  • 76
  • 129
  • You use no `.then` and you never resolve (only reject) ... this isn't even close to being salvageable code – Jaromanda X Mar 27 '16 at 11:02
  • Hence the "I'm completely new"... – Ben Fransen Mar 27 '16 at 11:03
  • I was recently at a talk that went over the new pieces of ES6 (which include promises). The speaker used promises along with a new iterator. Didn't follow it completely but maybe this will help: http://www.2ality.com/2015/02/es6-iteration.html – Donnie D'Amato Mar 27 '16 at 12:01
  • Thanks! I'll take a look at it.Hope it helps :) – Ben Fransen Mar 27 '16 at 12:02
  • Well, I wasn't able to figure it out while the result desired shouldn't be that hard to achieve. Only continue to the next ajax call when the previous is finished. Eventually I easily solved it using a timeout, a processing boolean and a counting variable. – Ben Fransen Mar 27 '16 at 15:53
  • There's a great way to chain variable numbers of promises at the end of @OscarPaz 's answer here: https://stackoverflow.com/a/22540276/1024735 – kevinmicke Oct 04 '18 at 20:50

1 Answers1

1

I do not think using timeout would give an efficient solution, a simple way to do it would be to add each promise call to 'then' of a single promise chain, example :

let promise = Promise.resolve(), // initialize promise chain
  someArray = [ ... ];

for(let i=0;i<someArray.length;i++)
  promise = promise.then(() => someCall(someArray[i]))

so your code, can be modified to below: (I have added resolve call in the end like Jaromanda X said)

var currentBatch = 0, promise = Promise.resolve();
while(currentBatch < totalElevationBatches) {
    promise = addToChain(promise, currentBatch, batchSize);
    currentBatch++;
}

promise.then(...) // write code inside then that would handle once all the batches are processed

function getRouteElevationChartDataBatch(batch, batchSize) {
    return new Promise(function(resolve, reject) {
        var elevator = new google.maps.ElevationService();
        var thisBatchPath = [];

        for (var j = batch * batchSize; j < batch * batchSize + batchSize; j++) {
            if (j < directions.routes[0].overview_path.length) {
                thisBatchPath.push(directions.routes[0].overview_path[j]);
            } else {
                break;
            }
        }

        elevator.getElevationAlongPath({
            path: thisBatchPath,
            samples: 256
        }, function (elevations, status) {
            if (status != google.maps.ElevationStatus.OK) {
                reject(status);
            }

            routeElevations = routeElevations.concat(elevations);
            resolve();
        });
    });
}

function addToChain(chain, batch, batchSize){
    return chain.then(function(){
        return getRouteElevationChartDataBatch(batch, batchSize);
    });
}
mido
  • 24,198
  • 15
  • 92
  • 117
  • Thanks a bunch for taking the time to write the answer; and also customize it to my code. This makes sense while the `let promise... ` syntaxis still confuses me. +10 and accepted, only I can give +1 ;) – Ben Fransen Mar 28 '16 at 15:04