Comportement de Promise.all avec les observables RxJS?

87

Dans Angular 1.x, j'aurais parfois besoin de faire plusieurs httpdemandes et de faire quelque chose avec toutes les réponses. Je jetterais toutes les promesses dans un tableau et appellerais Promise.all(promises).then(function (results) {...}).

Les meilleures pratiques Angular 2 semblent indiquer l'utilisation de RxJS Observableen remplacement des promesses dans les httpdemandes. Si j'ai deux ou plusieurs observables différents créés à partir de requêtes http, existe-t-il un équivalent à Promise.all()?

Corey Ogburn
la source

Réponses:

77

L'alternative la plus simple pour émuler Promise.allest d'utiliser l' forkJoinopérateur (il démarre toutes les observables en parallèle et joint leurs derniers éléments):

Un peu hors de portée, mais au cas où cela aiderait, au sujet du chaînage des promesses, vous pouvez utiliser un simple flatMap: Cf. Composition de la promesse RxJS (transmission de données)

user3743222
la source
1
si j'ai 2 appels, une promesse de retour et un autre retour observable, puis-je utiliser forkjoin? ou promise.all ()? ou personne, je dois laisser les 2 fonctions retourner le même type soit des promesses, soit des observables?
Joe Sleiman
1
Veuillez aider, forkJoin ne fonctionne pas lorsque les observables passés en paramètre n'émettent pas de valeurs. J'ai des observables vides et je veux toujours utiliser la fonctionnalité forkJoin mais cela ne fonctionne pas
Goga Koreli
18

Mise à jour de mai 2019 avec RxJs v6

A trouvé les autres réponses utiles, et a souhaité donner un exemple de réponse proposée par Arnaud sur l' zipusage.

Voici un extrait de code montrant l'équivalence entre Promise.allet le rxjs zip(notez aussi, dans rxjs6 comment zip est maintenant importé en utilisant "rxjs" et non en tant qu'opérateur).

import { zip } from "rxjs";

const the_weather = new Promise(resolve => {
  setTimeout(() => {
    resolve({ temp: 29, conditions: "Sunny with Clouds" });
  }, 2000);
});

const the_tweets = new Promise(resolve => {
  setTimeout(() => {
    resolve(["I like cake", "BBQ is good too!"]);
  }, 500);
});

// Using RxJs
let source$ = zip(the_weather, the_tweets);
source$.subscribe(([weatherInfo, tweetInfo]) =>
  console.log(weatherInfo, tweetInfo)
);

// Using ES6 Promises
Promise.all([the_weather, the_tweets]).then(responses => {
  const [weatherInfo, tweetInfo] = responses;
  console.log(weatherInfo, tweetInfo);
});

La sortie des deux est la même. L'exécution de ce qui précède donne:

{ temp: 29, conditions: 'Sunny with Clouds' } [ 'I like cake', 'BBQ is good too!' ]
{ temp: 29, conditions: 'Sunny with Clouds' } [ 'I like cake', 'BBQ is good too!' ]
Arcseldon
la source
13

forkJoin fonctionne bien aussi, mais je préférerais combineLatest car vous n'avez pas à vous soucier qu'il prenne la dernière valeur d'observables. De cette façon, vous pouvez simplement être mis à jour chaque fois que l'un d'eux émet également une nouvelle valeur (par exemple, vous récupérez un intervalle ou quelque chose).

Kakigoori
la source
1
Cela ne répond pas à mes besoins actuels mais je vais certainement l'utiliser bientôt.
Corey Ogburn
4
Cela n'atteint pas le même comportement que Promise.all (), mais c'est similaire à Promise.any ()
Purrell
si j'ai 2 appels, une promesse de retour et un autre retour observable, puis-je utiliser forkjoin? ou promise.all ()? ou personne, je dois laisser les 2 fonctions retourner le même type soit des promesses, soit des observables?
Joe Sleiman
1
@JoeSleiman un peu tard, mais vous pouvez choisir votre camp: Observable.fromPromise () avec Observable.zip () , ou Obserable.toPromise () avec Promise.all ()
Arnaud P
11

Sur reactivex.io forkJoin pointe en fait vers Zip , qui a fait le travail pour moi:

let subscription = Observable.zip(obs1, obs2, ...).subscribe(...);
Arnaud P
la source
"cela signifie que forkJoin n'émettra pas plus d'une fois et qu'il se terminera par la suite. Si vous avez besoin d'émettre des valeurs combinées non seulement à la fin du cycle de vie des observables passés, mais aussi tout au long de celui-ci, essayez à la place combineLatest ou zip." rxjs-dev.firebaseapp.com/api/index/function/forkJoin
Jeffrey Nicholson Carré
2
forkJoin attend la fin de toutes les observables, tandis que zip émet un tableau lorsque toutes les entrées émettent leur première valeur. zip peut émettre plusieurs fois. Si vous avez des appels http, cela ne fait aucune différence.
hgoebl le
Bon, j'obtiens la subtilité maintenant, bravo. Je n'avais pas réalisé que les sections linguistiques se développent-_-
Arnaud P