web-dev-qa-db-fra.com

RxJS Promise Composition (transmission de données)

Je suis tout nouveau sur Rx et j'ai du mal à trouver de la documentation sur la composition des promesses de telle sorte que les données de la première promesse soient passées dans la seconde et ainsi de suite. Voici trois promesses très basiques, les calculs sur les données ne sont pas importants, juste que quelque chose d'async doit être fait en utilisant les données de la promesse précédente.

 const p1 = () => Promise.resolve(1);
 const p2 = x => { const val = x + 1; return Promise.resolve(val); };
 const p3 = x => {
      const isEven = x => x % 2 === 0;
      return Promise.resolve(isEven(x));
 };

La façon traditionnelle de réaliser la composition dont je parle:

 pl().then(p2).then(p3).then(console.log);

Mon implémentation préférée est le compositeP et le pipeP de Ramda:

R.pipeP(p1, p2, p3, console.log)()

Il semble probable que Rx puisse gérer ce genre de situation assez couramment. Cependant, le plus proche que j'ai trouvé jusqu'à présent est de la comparaison RxJS à async (bibliothèque) ici https://github.com/Reactive-Extensions/RxJS/blob/master/doc/mapping/async/comparing .md :

 var Rx = require('rx'),
     fs = require('fs'),
     path = require('path');
 var file = path.join(__dirname, 'file.txt'),
     dest = path.join(__dirname, 'file1.txt'),
     exists = Rx.Observable.fromCallback(fs.exists),
     rename = Rx.Observable.fromNodeCallback(fs.rename),
     stat = Rx.Observable.fromNodeCallback(fs.stat);
 exists(file)
    .concatMap(function (flag) {
     return flag ?
         rename(file, dest) :
         Rx.Observable.throw(new Error('File does not exist.'));
    })
    .concatMap(function () {
        return stat(dest);
    })
   .forEach(
      function (fsStat) {
          console.log(JSON.stringify(fsStat));
      },
      function (err) {
          console.log(err);
      }
    );

concatMap semble prometteur, mais le code ci-dessus semble assez horrible. J'avais également des problèmes avec mon exemple parce que Rx.Observable.fromPromise (p1) ne fonctionnera pas car il attend une promesse elle-même, pas une fonction, et Rx.Observable.defer (p1) ne semble pas transmettre des paramètres comme le exemple.

Merci!

Question similaire mais sans transmission de données: chaînage des promesses avec RxJS

16
low_ghost

Je n'ai pas tout lu, mais si vous voulez obtenir la même chose que pl().then(p2).then(p3).then(console.log);, avec p étant une fonction renvoyant des promesses, vous pourriez faire quelque chose comme (exemple ici )

Rx.Observable.fromPromise(p1())
             .flatMap(function(p1_result){return p2(p1_result);})
             .flatMap(function(p2_result){return p3(p2_result);})

Ou le plus symétrique:

 var chainedPromises$ = 
     Rx.Observable.just()
             .flatMap(p1)
             .flatMap(p2)
             .flatMap(p3);

Maintenant, si vous souhaitez exécuter un rappel séquentiel enveloppé à travers fromCallback ou fromNodeCallback, vous pouvez faire quelque chose comme:

function rename (flag){
  return flag
          ? rename(file,dest).flatMap(return Rx.Observable.just(dest))
          : Rx.Observable.throw(new Error('File does not exist.'));
}

Rx.Observable.just(file)
             .flatMap(exists)
             .flatMap(rename)
             .flatMap(stat)

Ce dernier code n'a pas été testé, alors tenez-moi au courant si cela fonctionne. Dernier commentaire, cela devrait fonctionner si à chaque point vous n'avez qu'une seule valeur produite (comme une promesse). Si vous avez plusieurs fichiers au lieu d'un, avec flatMap vous pourriez avoir des problèmes de commande (si la commande vous intéresse), dans ce cas, vous pouvez utiliser concatMap en remplacement.

23
user3743222