问题
In a component, in ngOnInit() I've got two subscriptions to a data service. I want to do some processing once both subscriptions have returned. Whats the best way to do this? I can just process at the end of each, this just seems a little inefficient and won't work for which ever subscription activates first,
Thanks,
Component.TS
ngOnInit()
{
this.dataService.dataA().subscribe((dataAJSON) =>
{
this.dataA= dataAJSON
}
this.dataService.dataB().subscribe((dataBJSON) =>
{
this.dataB= dataBJSON
}
DataService
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
@Injectable()
export class PMDataService
{
constructor(public http : Http)
{
}
dataA()
{
var dataA: any;
var json;
dataA= this.http.get("./assets/dataa.json")
.map(res => res.json());
return dataA
}
dataB()
{
var dataB: any;
var json;
dataB= this.http.get("./assets/datab.json")
.map(res => res.json());
return dataB
}
}
回答1:
You can use Observable#forkJoin function on the Observables. It emits the last value from each when all observables complete,
Observable.forkJoin(this.dataService.dataA(), this.dataService.dataB())
.subscribe(val => /* val is an array */)
回答2:
The method used depends on how you want to receive the data:
You can use the zip function. Emits once when all have emitted once. So similar to Promise.all
except not on completion.
Observable.zip(obs1, obs2).subscribe((val) => { ... });
You can use the forkJoin function. Emits once when all have completed. So exactly like Promise.all
.
Observable.forkJoin(obs1, obs2).subscribe((val) => { ... });
You can use the merge function. Emits in order of emission so could be 1st then 2nd or 2nd then 1st:
obs1.merge(obs2).subscribe((val) => { ... });
You can use concat function. Emits in order 1st then 2nd regardless if 2nd emits first:
obs1.concat(obs2).subscribe((val) => { ... });
It's best practice to split these up into a couple lines for clarity.
const obs1 = Rx.Observable.of(1,2,3);
const obs2 = Rx.Observable.of(1,2,3);
const example = Observable.zip(obs1, obs2);
//const example = Observable.forkJoin(obs1, obs2);
//const example = obs1.merge(obs2);
//const example = obs1.concat(obs2);
example.subscribe(val => { ... });
回答3:
You could use the operator Zip
or CombineLatest
from rxjs.
See ReactiveX operators
You could do something like this:
Observable.zip(
this.http.get("./assets/dataa.json"),
this.http.get("./assets/dataa.json")
.take(1)
.map(values => [values[0].json(), values[1].json()])
.subscribe(values => {
// do something with my values
});
回答4:
You could You can use concat to combine the observables and return a single observable.
Subscribe to observables in order as previous completes, emit values
changed service code
import 'rxjs/add/operator/concat';
export class PMDataService
{
data(){
return this.dataA().concat(this.dataB());
}
// methods dataA and dataB are unchanged, some of the constructor
}
Component code
ngOnInit(){
this.dataService.data().subscribe((dataJSON) =>
{
this.dataA= dataAJSON[0];
this.dataB= dataAJSON[1];
}
}
来源:https://stackoverflow.com/questions/47338271/angular-detecting-when-two-subscriptions-have-updated