Promise.all behavior with RxJS Observables?
Asked Answered
T

4

122

In Angular 1.x I would sometimes need to make multiple http requests and do something with all the responses. I would throw all the promises in an array and call Promise.all(promises).then(function (results) {...}).

Angular 2 best practices seem to point towards the use of RxJS's Observable as a replacement to promises in http requests. If I have two or more different Observables created from http requests, is there an equivalent to Promise.all()?

Tarter answered 24/2, 2016 at 16:44 Comment(3)
Duplicate of Promise.all() with RxJSKoal
@Koal Considering this question has 5x the upvotes and 3x the views, maybe the other one should be marked as the duplicate despite being asked earlier?Tarter
I think the later question is the duplicate. I think it does not matter that this question has more upvotes and more views.Koal
B
99

The more straightforward alternative for emulating Promise.all is to use the forkJoin operator (it starts all observables in parallel and join their last elements):

A bit out of scope, but in case it helps, on the subject of chaining promises, you can use a simple flatMap : Cf. RxJS Promise Composition (passing data)

Berky answered 24/2, 2016 at 17:20 Comment(2)
if i have 2 calls one return promise and another return observable can i user forkjoin ? or promise.all() ? or no one , i have to let the 2 functions return same type either promises or observable ?Groveman
Please help, forkJoin doesn't work when observables passed as parameter don't emit values. I have void Observables and still want to use forkJoin functionality but it is not workingBrandon
E
32

Update May 2019 using RxJs v6

Found the other answers useful, and wished to offer an example for the answer offered by Arnaud about zip usage.

Here is a snippet showing the equivalence between Promise.all and the rxjs zip (note also, in rxjs6 how zip now gets imported using "rxjs" & not as an operator).

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);
});

The output from both are the same. Running the above gives:

{ 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!' ]
Enwreathe answered 5/5, 2019 at 14:52 Comment(2)
Is there a important distinction which results in the suggestion of using observables over simple Promise.all()Together
zip: If one of the observables complete, then the operator stops emitting any value even if the other observables have not completed javascript.plainenglish.io/…Endoergic
D
14

forkJoin works fine too, but I'd prefer combineLatest since you don't need to worry about it taking the last value of observables. This way, you can just get updated whenever any of them emit a new value too (e.g. you fetch on an interval or something).

Dash answered 25/2, 2016 at 4:54 Comment(4)
This doesn't meet my current needs but I will definitely be using that soon.Tarter
That doesn't achieve the same behavior as Promise.all(), but it's similar to Promise.any()Moltke
if i have 2 calls one return promise and another return observable can i user forkjoin ? or promise.all() ? or no one , i have to let the 2 functions return same type either promises or observable ?Groveman
@JoeSleiman a bit late, but you can pick your side: Observable.fromPromise() together with Observable.zip(), or Obserable.toPromise() with Promise.all()Powwow
P
13

On reactivex.io forkJoin actually points to Zip, which did the job for me:

let subscription = Observable.zip(obs1, obs2, ...).subscribe(...);
Powwow answered 28/7, 2017 at 16:11 Comment(3)
"that means forkJoin will not emit more than once and it will complete after that. If you need to emit combined values not only at the end of lifecycle of passed observables, but also throughout it, try out combineLatest or zip instead." rxjs-dev.firebaseapp.com/api/index/function/forkJoinCue
forkJoin waits for all the observables to end, while zip emits an array when all inputs emit their first value. zip might emit many times. If you have http-calls, it makes no difference.Quean
Right, I get the subtlety now, cheers. I hadn't realized that the language sections expand -_-Powwow

© 2022 - 2024 — McMap. All rights reserved.