What is the proper way to handle concatenation of

2019-07-25 05:04发布

问题:

I have 5 different URLs that each return data in the from of an array of objects. I want to concat these objects into a single array that I store local to my ANgular2 componenent. Right now, I do something like this in my ngOnInit:

this.myHttpService.graburl1data()
    .subscribe(
        response => {
            if(!this.mylist) {
                this.mylist = []
                this.mylist = this.mylist.concat(response);
            } else {
                this.mylist = this.mylist.concat(response);
            }

            this.myHttpService.graburl2data()
                .subscribe(
                    response => {
                        if(!this.mylist) {
                            this.mylist = []
                            this.mylist = this.mylist.concat(response);
                        } else {
                            this.mylist = this.mylist.concat(response);
                        }
                    });
        });

There has to be a better way, please help!

回答1:

Suppose you have two requests and each returns an observable that emits an array as a stream value:

const response1 = of([1, 2, 3]);
const response2 = of([4, 5, 6]);

You want to get those values as a stream of values - flattened. You can use a combination of operators to do that:

const merged = merge(response1, response2).mergeMap((a) => {
  return a;
});

merged.subscribe((v) => {
  console.log(v);
});

You will get the following output:

1
2
3
4
5
6

In your case you will obtains the response observables by calling the http:

const response1 = this.myHttpService.graburl1data(),
const response2 = this.myHttpService.graburl2data()
...

So, the final code is:

import { merge } from 'rxjs/observable/merge';
import 'rxjs/add/operator/mergeMap';

const merged = merge(
  this.myHttpService.graburl1data(),
  this.myHttpService.graburl2data()
).mergeMap((a) => {
  return a;
});

merged.subscribe((v) => {
  console.log(v);
});


回答2:

Your snippet seems to suggest that there is no dependency between the requests, so you can use forkJoin to peform them in parallel:

import { Observable } from "rxjs/Observable";
import "rxjs/add/observable/forkJoin";

Observable.forkJoin(
  this.myHttpService.graburl1data(),
  this.myHttpService.graburl2data()
)
.subscribe(
  (responses) => {
    // ... responses[0] is the response from this.myHttpService.graburl1data
    // ... etc.
  }
);

responses will be an array of the responses in the order in which the request observables were passed to forkJoin.

If you want the requests performed in series, use concat and toArray instead:

import { Observable } from "rxjs/Observable";
import "rxjs/add/observable/concat";
import "rxjs/add/operator/toArray";

Observable.concat(
  this.myHttpService.graburl1data(),
  this.myHttpService.graburl2data()
)
.toArray()
.subscribe(
  (responses) => {
    // ... responses[0] is the response from this.myHttpService.graburl1data
    // ... etc.
  }
);