web-dev-qa-db-fra.com

Comment enchaîner séquentiellement les promesses avec angularjs $ q?

Dans la bibliothèque de promessesQ, vous pouvez effectuer les opérations suivantes pour enchaîner les promesses:

var items = ['one', 'two', 'three'];
var chain = Q();
items.forEach(function (el) {
  chain = chain.then(foo(el));
});
return chain;

cependant, ce qui suit ne fonctionne pas avec $ q :

var items = ['one', 'two', 'three'];
var chain = $q();
items.forEach(function (el) {
  chain = chain.then(foo(el));
});
return chain;
14
redgeoff

Utilisez simplement la fonction $ q.when ():

var items = ['one', 'two', 'three'];
var chain = $q.when();
items.forEach(function (el) {
  chain = chain.then(foo(el));
});
return chain;

Remarque: foo doit être une usine, par exemple.

function setTimeoutPromise(ms) {
  var defer = $q.defer();
  setTimeout(defer.resolve, ms);
  return defer.promise;
}

function foo(item, ms) {
  return function() {
    return setTimeoutPromise(ms).then(function () {
      console.log(item);
    });
  };
}

var items = ['one', 'two', 'three'];
var chain = $q.when();
items.forEach(function (el, i) {
  chain = chain.then(foo(el, (items.length - i)*1000));
});
return chain;
28
redgeoff

Redgeoff, votre propre réponse est la façon dont je habitué traduit un tableau en une série de promesses enchaînées.

Le modèle de facto émergent est le suivant:

function doAsyncSeries(arr) {
    return arr.reduce(function (promise, item) {
      return promise.then(function(result) {
        return doSomethingAsync(result, item);
      });
    }, $q.when(initialValue));
}

//then
var items = ['x', 'y', 'z'];
doAsyncSeries(items).then(...);

Remarques: 

  • .reduce est un code javascript brut qui ne fait pas partie d'une bibliothèque.
  • result est le résultat/les données asynchrones précédent et est inclus pour des raisons de complétude. La result initiale est initialValue. S'il n'est pas nécessaire de transmettre le résultat, laissez-le simplement de côté.
  • adapter $q.when(initialValue) en fonction de la promesse que vous utilisez.
  • dans votre cas, doSomethingAsync est foo (ou ce que foo () renvoie?) - dans tous les cas, une fonction.

Si vous êtes comme moi, le motif ressemblera, à première vue, à un refoulement impénétrable, mais une fois que votre œil aura été harmonisé, vous commencerez à le considérer comme un vieil ami. 

Modifier

Voici un demo , conçu pour démontrer que le modèle recommandé ci-dessus exécute ses appels doSomethingAsync() de manière séquentielle, et non immédiatement lors de la construction de la chaîne, comme suggéré dans les commentaires ci-dessous.

35
Roamer-1888

Ayant ceci:

let items = ['one', 'two', 'three'];

Une ligne (enfin, 3 pour la lisibilité):

return items
    .map(item => foo.bind(null, item))
    .reduce($q.when, $q.resolve());
4
var when = $q.when();

for(var i = 0; i < 10; i++){
    (function() {
         chain = when.then(function() {
        return $http.get('/data');
      });

    })(i); 
}
4
pabloRN

D'une manière peut-être plus simple que celle de la réponse de redgeoff , si vous n'en avez pas besoin, vous pouvez enchaîner les promesses à l'aide de $q.when() combiné à .then(), comme indiqué au début de ce message . return $q.when() .then(function(){ return promise1; }) .then(function(){ return promise2; });

3
Matthias

Je préfère préparer des fonctions qui renverront des promesses en utilisant angular.bind (ou Function.prototype.bind), puis en les liant à une chaîne en utilisant le raccourci-raccourci. Par exemple

// getNumber resolves with given number
var get2 = getNumber.bind(null, 2);
var get3 = getNumber.bind(null, 3);
[get2, get3].reduce(function (chain, fn) {
   return chain.then(fn);
}, $q.when())
.then(function (value) {
   console.log('chain value =', value);
}).done();
// prints 3 (the last value)
2
gleb bahmutov

Votre réponse est correcte. Cependant, je pensais fournir une alternative. Vous pourriez être intéressé par $ q.serial si vous vous retrouvez souvent à enchaîner les promesses en série.

var items = ['one', 'two', 'three'];
var tasks = items.map(function (el) {
  return function () { foo(el, (items.length - i)*1000)); });
});

$q.serial(tasks);

function setTimeoutPromise(ms) {
  var defer = $q.defer();
  setTimeout(defer.resolve, ms);
  return defer.promise;
}

function foo(item, ms) {
  return function() {
    return setTimeoutPromise(ms).then(function () {
      console.log(item);
    });
  };
}
1
Steven Wexler