$q.all() 在 Angularjs 中多次调用

$q.all() multiple calls in Angularjs

我有一个调用点击事件的函数。它有一个驱动程序列表,我希望通过 Google 方向服务针对每个驱动程序进行 ETA。这是我的代码:

var deferred = $q.defer();
var urlCalls = [];

function getDriversEta(jobLoc, drivers) { //this function gets invoke on click.
    angular.forEach(drivers, function (value, key) {
        value.eta = undefined;
        urlCalls.push(GetDriverMatrix(jobLoc.lat, jobLoc.lon,
            value.Location.Latitude, value.Location.Longitude, function (response) {
                value.eta = formatSecondsToTime(response.routes[0].legs[0].duration.value);
                deferred.resolve(value);
            }));
    });
    $q.all(urlCalls).then(
        function (results) {
            var check = results;
        },
        function (errors) {
            //deferred.reject(errors);
        },
        function (updates) {
            //deferred.update(updates);
        });
}

function GetDriverMatrix(pickupLat, pickupLon, driverLat, driverLon, callBack) {
    var directionsService = new google.maps.DirectionsService();
    var directionsRequest = {
        origin: new google.maps.LatLng(driverLat, driverLon),
        destination: new google.maps.LatLng(pickupLat, pickupLon),
        travelMode: google.maps.DirectionsTravelMode.DRIVING,
        unitSystem: google.maps.UnitSystem.METRIC
    };
    directionsService.route(directionsRequest, function (response, status) {
        if (status == google.maps.DirectionsStatus.OK) {
            callBack(response);
        }
    });

    return deferred.promise;
}

它第一次工作正常,但给出了重复的值。但是在第二次点击事件中,$q.all() 的函数会在回调响应之前触发。我在这里做错了什么?我是新手。

你有几个问题:

1) 您正在执行多项异步操作,但您只有一个延迟对象,所有对象都在使用该对象。因此,一旦他们中的任何一个解决了延迟,他们就会有效地全部解决。相反,他们每个人都需要自己的。
2) GetDriverMatrix 似乎在同时执行回调方法和承诺方法。只选一个(我推荐 promises)。

那么让我们从修复 GetDriveMatrix 开始:

//** Callback parameter removed
function getDriverMatrix(pickupLat, pickupLon, driverLat, driveLon) {
    var deferred = $q.defer(); //** create a new deferred each time
    var directionsService = new google.maps.DirectionsService();
    var directionsRequest = {
        origin: new google.maps.LatLng(driverLat, driverLon),
        destination: new google.maps.LatLng(pickupLat, pickupLon),
        travelMode: google.maps.DirectionsTravelMode.DRIVING,
        unitSystem: google.maps.UnitSystem.METRIC
    };
    directionsService.route(directionsRequest, function (response, status) {
        if (status == google.maps.DirectionsStatus.OK) {
        deferred.resolve(response); //** resolve instead of calling callback
    } else {
        deferred.reject(response); //** reject if there's an error
    }
    return deferred.promise;
});

现在开始使用它,你基本上是在正确的轨道上,但我会改变一些东西:

1) 由于我删除了 getDriverMatrix 的回调部分,我们将改用 promise。
2) 将 promises 数组放在函数内部,而不是外部。没有其他人需要看到这个数组,所以没有必要公开它
3) 我不会使用 foreach 然后推入数组,而是使用 array.map。它专为此类情况而设计,让您无需手动进行推送。

function getDriversEta(jobLoc, drivers) {
    //** Using array.map to produce a new array of promises
    var promises = drivers.map(function (driver) {
        return GetDriverMatrix(jobLoc.lat, jobLoc.lon, driver.Location.latitude, driver.Location.longitude)
            //** using the .then method instead of callback
            .then(function (response) {
                driver.eta = formatSecondsToTime(response.routes[0].legs[0].duration.value);
                return driver;
            });
    });

    $q.all(promises).then(
        function (results) {
            var check = results;
        },
        function (errors) {

        },
        function (updates) {

        });
}