web-dev-qa-db-fra.com

Passer la variable à promettre dans une boucle

J'ai une promesse dans une boucle, et je ne sais pas comment passer certaines variables de portée dans le gestionnaire de promesses.

for(var i in superarray){
    MyService.get(superarray[i].externalID).then(function(r){
        console.debug(i);
});

MyService est un service fonctionnel, avec une méthode get qui renvoie une promesse.

app.factory('MyService', function($http,$q) {
  return {
     get : function(itemID){
        var deferred = $q.defer();
        $http.get('/someresturl/'+itemID).then(function(e) { 
                deferred.resolve(e.data);
        }, function(reason) {
                deferred.reject(reason);
        });
        return deferred.promise;
    }
});

Dans ma console, la console.debug n'affiche logiquement pas 1,2,3,4,5. Mais 5,5,5,5,5. (il y a 5 éléments dans mon superarray).

Comment puis-je transmettre la valeur "i" dans la portée de ma promesse, afin de pouvoir l'utiliser dans le then ()?

C'est possible?

35
Ant

Une façon consiste à capturer i dans une fermeture:

for(var i in superarray) {
    (function(i) {
        MyService.get(superarray[i].externalID).then(function(r) {
            console.debug(i);
        });
    })(i);
}

Une autre façon serait de faire en sorte que itemID soit répété en tant que propriété de r:

for(var i in superarray){
    MyService.get(superarray[i].externalID).then(function(r) {
        console.debug(r.itemID);
    });
};
74
Beetroot-Beetroot

Au moment de l'exécution de votre rappel, i fera référence au dernier élément de votre tableau. Vous pouvez utiliser une fermeture et capturer la valeur actuelle de i:

for (var i in superarray){
    (function(j) {
        MyService.get(superarray[j].externalID).then(function(r) {
            console.debug(j);
        });
    })(i);
}
15
Blender

Vous pouvez simplifier un peu le code en utilisant le Array.prototype.forEach Intégré:

superarray.forEach(function (item, index) {
    MyService.get(item.externalID).then(function(r) {
        console.debug(index);
    });
});
5
Stuart K

J'aurais juste commenté la solution acceptée mais je n'ai actuellement pas assez de réputation.

Je pense que la deuxième solution consistant à répéter l'itemID en tant que propriété de r fonctionnerait très bien également.

gestionnaire de promesses simple:

angular.module('myApp', []).run(['MyService', function(MyService) {
  superarray = [1, 2, 3, 4, 5];


  for(var i in superarray) {
    MyService.get(superarray[i]).then(function(returned) {
      console.log(returned.id);
    });
  }

}]);

MyService retournant itemID en tant que propriété de l'objet retourné:

angular.module('myApp')
.factory('MyService', function($http,$q) {
  return {
     get : function(itemID){
        var deferred = $q.defer();

        $http.get('www.google.com').then(function(e) { 
                var returnObject = {
                  'data': e.data,
                  'id': itemID
                };
                deferred.resolve(returnObject);
        }, function(reason) {
                deferred.resolve(reason);
        });
        return deferred.promise;
    }
}});

Voici un exemple de travail sur plnkr .

3
jleljedal

Essayez cette solution, j'ai utilisé $ q.all et j'ai ajouté mon paramètre dans le tableau. Ça a marché

   for(var i in superarray){
      $q.all([MyService.get(superarray[i].externalID), i]).then(function(results){
        var r = results[0];
        var i = results[1];
        console.debug(i);
      });
    }
1
GioP