Angular.JS 循环保持 运行 而循环内的服务调用正在等待承诺

Angular.JS loop keeps running while a service call inside the loop is waiting for promise

"AddDistance" 是一个插入到数据库的函数, 问题是 hash[k][2] 值随着循环向前跳转,而 "distance"(服务承诺)仍在等待,结果我向我的数据库插入了错误的行。

我如何在 "AddDistance()" 运行 之前保持跳转到下一个对象的循环,我应该使用 Q$、While、.then() 吗?

我尝试了上面的方法但失败了,可能是没有做对。

请指教...

 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;

        });

    }

您可以执行如下操作,但它不会保持循环:

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
});

请注意,只要下一次迭代不依赖于上一次迭代,此方法就可以正常工作。

您可以通过将 promise 链接在一起而不是 运行ning 并行地确保 运行ning 操作一次一个 运行 。但需要注意确保参数正确传递,因为循环将在任何 long-running 函数被调用之前完成。

因为函数是按顺序执行的,所以您可以将结果存储在数组中并确保它们是有序的。

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();
       });
    });
}