0

Problem: I have to fetch both configuration and data from the server. The data can be rendered only after the configuration is fetched and loaded.

How I want my problem solved: I want to fetch both at the same time, using Angular's HttpClient. However, the callback for configuration must be executed first.

Attempt 1: I tried concat() from this SO question:

concat(
    this.fetchConfig().pipe(take(1)),
    this.fetchData().pipe(take(1))
).subscribe(val => {
    if (isConfig(val)) {
        // This must be executed before the below populate(val);
        // This one is slow, blocking, so it must be executed
        // as soon as possible.
        load(val);
    } else {
        // val is data
        populate(val);
    }
});

However, I don't think it accomplishes my goal. I think Observable is a lazy executor, it only executes if there's something subscribe() to it. concat() delays the subscription of the callback to fetchData(), which also delays the actual fetching of data from the server.

Attempt 2: Use forkJoin(): forkJoin() only emits once all Observable emitted. The fetching of configuration is usually faster, then I want to execute its callback as soon as possible, so when the data is ready, the configuration may already be fully loaded.

How can I achieve this? And, btw, how can I fix my callback? Have some code to determine if val is data or configuration is very very ugly.

Edit: I edit the code for more clarification. Basically, I overengineered it. A forkJoin() should be OK for my case, as load(val) is pretty fast. However, I still want to push this, by forcing load(val) to be slow (this is actually what I thought this morning), so it has to be executed as soon as possible AND before populate(val).

Right now I'm thinking of making an Observable with it and do chaining.

Minh Nghĩa
  • 854
  • 1
  • 11
  • 28
  • Checkout the answer for https://stackoverflow.com/questions/45945846/how-to-make-2-dependent-http-request-in-angular-2. You will need to use the switchMap from rxjs – Sachin Gupta Oct 05 '19 at 05:26
  • Possible duplicate of [how to make 2 dependent http request in Angular 2](https://stackoverflow.com/questions/45945846/how-to-make-2-dependent-http-request-in-angular-2) – Sachin Gupta Oct 05 '19 at 05:27
  • You only need switchMap if the second request needs the result of the first request otherwise you are unnecessarily waiting for the first request to complete before starting the second. Using a combine latest you can fire both requests at once – Adrian Brand Oct 05 '19 at 07:42
  • what does `load(val)` do? Is it a http-request or what?` – AT82 Oct 05 '19 at 12:40
  • @AJT82 it loads my configurations :v There's some calculation, but it's fast. Yesterday I thought it had to be slow. – Minh Nghĩa Oct 06 '19 at 02:11
  • why not call `load()` first and then call `populate()` after that, if the order matters? – AT82 Oct 06 '19 at 07:58

2 Answers2

2

Combine latest will emit once both requests have completed

combineLatest(
    this.getJConfig(),
    this.fetchData()
).subscribe(([config, data]) => {
  // Use config
  // Then use data
});

No need for a take one on a http request as the observable completes once the request has finished.

There is no need to worry about using config as soon as it has finished as the amount of time it takes JavaScript to process the response is insignificant compared to the amount of time the request takes to complete.

If you really want to preserve order I came up with this convoluted beast a while ago for someone else RxJS: MergeMap with Preserving Input order

Adrian Brand
  • 20,384
  • 4
  • 39
  • 60
-1

Maybe not perfect RxJS but you could do...

const configFetch = this.fetchConfig().toPromise();
const dataFetch = this.fetchData().toPromise();
const config = await configFetch;
processConfig(config);
const data = await dataFetch;
processData(data);
Pace
  • 41,875
  • 13
  • 113
  • 156