2017-06-08 1 views
2

Je travaille sur une fonction qui calcule la distance entre un objet donné et un certain nombre d'autres endroits avec l'aide de Google Distance Matrix qui est bien sûr asynchrone avec des promesses.

Lorsque le nombre de places est de un, tout fonctionne très bien. Mais une fois que j'ai plus d'une promesse, $ q.all ne fait rien: il ne se résout pas en succès ni en erreur. Bien que j'ai vérifié dans la console que les appels à la matrice de distance de Google se produisent et renvoient un résultat correct. Toute idée de ce qui peut être en jeu ici? Je utilise AngularJS 1.6.4. Faites-moi savoir si vous avez besoin de plus de détails. Merci!

var requests = []; 
for (var i = 0; i < ctrl.places.length; i += 1) { 
    var deferred = $q.defer(); 
    requests.push(deferred.promise); 
    var destination = ctrl.places[i].latLng; 
    service.getDistanceMatrix({ 
     origins: [ctrl.origin], 
     destinations: [destination[0] + "," + destination[1]], 
     travelMode: 'DRIVING' 
    }, function(response, status) { 
     if (status === 'OK') { 
      deferred.resolve(response.rows[0].elements[0].distance.text); 
     } 
    }); 
} 

$q.all(requests).then(function(result) { 
    ctrl.distances = result; 
}); 

Répondre

1

Raison pour laquelle il ne fonctionne pas

Au moment où les résolutions d'appel de service et le gestionnaire de rappel est invoquée, l'attribut deferred fait référence à l'objet différé dernier créé par la boucle for. Donc, en effet, vous effectuez toujours un resolve sur le tout dernier objet deferred qui a été créé.

Solution:

Créer une nouvelle fonction:

function getDistanceMatrixForDestination (destination, origins) { 
    var deferred = $q.defer(); 
    service.getDistanceMatrix({ 
     origins: [origins], 
     destinations: [destination[0] + "," + destination[1]], 
     travelMode: 'DRIVING' 
    }, function(response, status) { 
     if (status === 'OK') { 
      deferred.resolve(response.rows[0].elements[0].distance.text); 
     } else { 
      deferred.reject(); 
     } 
    }); 
    return deferred.promise; 
} 

Changer votre code existant à ceci:

var requests = []; 
for (var i = 0; i < ctrl.places.length; i += 1) { 
    var destination = ctrl.places[i].latLng; 
    requests.push(getDistanceMatrixForDestination (destination, ctrl.origins)); 
} 

$q.all(requests).then(function(result) { 
    ctrl.distances = result; 
}); 
+0

travaillé comme un charme! Merci beaucoup! J'ai passé des heures à devenir fou! – Nat

2

Votre problème est que var est pas bloquer scope, donc la valeur de deferred appartiendra toujours à l'itération finale de votre boucle au moment où l'un de vos rappels a re invoqué. Une conséquence de cette volonté que le différé plus tôt ne sera jamais résolu et le $q.all semblera se bloquer.

La façon la plus simple de résoudre c'est de changer votre utilisation de var-let pour tirer parti de la portée du bloc:

let deferred = $q.defer(); 
+0

J'aime votre solution de délimitation de bloc. C'est simple. Mais, ne pensez-vous pas que le support du navigateur sera un problème? – CodeWarrior