0

"AddDistance" is an insert to DB function, the problem is that hash[k][2] value jumps forward with the loop while "distance"(the service promise) is still waiting, and as result i insert wrong row to my DB.

how do i hold the loop from jumping to the next object before "AddDistance()" ran, should i use Q$, While, .then()?

i tried the above but failed, probably didn't do it correctly.

Please advise...

 for (var k in hash)
    {
         GoogleMaps(hash[k][0], hash[k][1], function (x) {
            var distance = x.rows[0].elements[0].distance.value;
            distance = parseInt(distance / 1000);
            AddDistance({ CityID1: hash[k][2], CityID2: $scope.CompanyCity.Id, DistanceKM: distance });
            console.log(distance);
            //return distance;

        });

    }
tomersss2
  • 135
  • 12

2 Answers2

1

You can ensure the long running operations run one at a time by chaining the promises together instead of running them in parallel. Some care is needed though to ensure the parameter gets passed through correctly as the loop will have completed before any of the long-running functions get called.

Because the functions execute in sequence you can store the results in an array and be sure they are in order.

var promise = $q.resolve();
var distances = [];

for (var k in hash) {
    promise = chainPromise(promise, callGoogleMaps, k);
};

promise.then(function () {
    console.log('forEach loop completed. Do Something after it...',
      distances);
});

function chainPromise(promise, fn, k) {
    return promise.then(function() { return fn(k); });
}

function callGoogleMaps(k) {
    return $q(function(resolve) {
       //sample of a long-running operation inside loop...
       GoogleMaps(hash[k][0], hash[k][1], function (x) {
         var distance = x.rows[0].elements[0].distance.value;
         distance = parseInt(distance / 1000);
         AddDistance({ CityID1: hash[k][2], CityID2: $scope.CompanyCity.Id, DistanceKM: distance });
         console.log(distance);
         distances.push(distance);
         resolve();
       });
    });
}
Duncan
  • 92,073
  • 11
  • 122
  • 156
  • Thanks for ur help, I'm sorry in advance but i won't be able to give u a feedback in the next 2 days until i'll understand all the new areas ur answer brings out for me – tomersss2 Feb 13 '17 at 21:41
0

You can do something like below, however it will not hold the loop:

var loopPromises = [];
var distanceList = [];

for (var k in hash) {
    var deferred = $q.defer();
    loopPromises.push(deferred.promise);
    //sample of a long-running operation inside loop...
    distanceList[k] = GoogleMaps(hash[k][0], hash[k][1], function (x) {
        var distance = x.rows[0].elements[0].distance.value;
        distance = parseInt(distance / 1000);
        AddDistance({ CityID1: hash[k][2], CityID2: $scope.CompanyCity.Id, DistanceKM: distance });
        console.log(distance);
        //return distance;
        deferred.resolve(distance);
    });    
};

$q.all(loopPromises).then(function () {
    console.log('forEach loop completed. Do Something after it...');
    //use the distanceList here
});

Note that this works fine as long as the next iteration doesn't depend on the previous one.

Yaser
  • 5,609
  • 1
  • 15
  • 27
  • Hi, when u split it to 2 different range u create a new problem, now i some how need to sync the hash[k][0], hash[k][1] in the loop with the $q i'll also need to pass the parameters: hash[k][2] and the distance response – tomersss2 Feb 13 '17 at 21:22
  • check the update on how to use resolve to return the distance – Yaser Feb 13 '17 at 21:31