117

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()?

ryanrhee
  • 2,550
  • 4
  • 23
  • 25
Corey Ogburn
  • 24,072
  • 31
  • 113
  • 188
  • Duplicate of [Promise.all() with RxJS](https://stackoverflow.com/questions/35247310/promise-all-with-rxjs) – BuZZ-dEE Nov 22 '22 at 09:37
  • @BuZZ-dEE 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? – Corey Ogburn Nov 29 '22 at 23:18
  • I think the later question is the duplicate. I think it does not matter that this question has more upvotes and more views. – BuZZ-dEE Dec 20 '22 at 10:37

4 Answers4

97

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)

Mick
  • 8,203
  • 10
  • 44
  • 66
user3743222
  • 18,345
  • 5
  • 69
  • 75
  • 1
    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 ? – Joe Sleiman Jun 12 '17 at 07:40
  • 1
    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 working – Goga Koreli Nov 16 '18 at 12:39
30

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!' ]
arcseldon
  • 35,523
  • 17
  • 121
  • 125
  • Is there a important distinction which results in the suggestion of using observables over simple Promise.all() – Harshal Sep 06 '22 at 05:30
13

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).

kakigoori
  • 1,218
  • 10
  • 20
  • 1
    This doesn't meet my current needs but I will definitely be using that soon. – Corey Ogburn Feb 25 '16 at 05:34
  • 6
    That doesn't achieve the same behavior as Promise.all(), but it's similar to Promise.any() – Purrell Sep 08 '16 at 20:26
  • 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 ? – Joe Sleiman Jun 12 '17 at 07:40
  • 1
    @JoeSleiman a bit late, but you can pick your side: [Observable.fromPromise()](https://www.learnrxjs.io/operators/creation/frompromise.html) together with [Observable.zip()](http://reactivex.io/documentation/operators/zip.html), or [Obserable.toPromise()](https://www.learnrxjs.io/operators/utility/topromise.html) with Promise.all() – Arnaud P Jul 28 '17 at 15:59
13

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

let subscription = Observable.zip(obs1, obs2, ...).subscribe(...);
Arnaud P
  • 12,022
  • 7
  • 56
  • 67
  • "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." https://rxjs-dev.firebaseapp.com/api/index/function/forkJoin – Jeffrey Nicholson Carré Jan 11 '20 at 12:34
  • 5
    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. – hgoebl Apr 30 '20 at 14:30
  • Right, I get the subtlety now, cheers. I hadn't realized that the language sections expand `-_-` – Arnaud P Apr 30 '20 at 20:54