我有一种情况,我必须同时触发2个GET请求:
我如何用rxjs实现呢?
我知道我可以压缩多个请求,但是到目前为止我看到的所有示例都只有1个错误处理块,但是在这里我需要区分两种错误情况。
预先感谢
答案 0 :(得分:1)
除了解决方案,我还有更多解决方法。 您的要求是触发并行请求,并根据第一个请求的响应取消第二个。
可以使用forkJoin
进行并行请求,但是所有可观察对象可以一起解决,
merge()
也将触发并行请求,但是任何响应都可以按任何顺序进行。使用merge(),我们将无法确定哪个响应来自哪个Observable。如果您可以自由修改返回的observable并添加一个标志以指示有关Observable索引,则可以使用一些额外的标志和代码来实现它:
export class AppComponent {
name = 'Angular';
obsOne = of('First Obs').pipe(map((res) => {
return {
firstObs: true,
result: res
}
}))
obsTwo = of('Second Obs').pipe(delay(6000))
secondObsReturned = false
timerHandle
obsSubcription: Subscription;
ngOnInit() {
this.obsSubcription = merge(this.obsOne, this.obsTwo).subscribe((data) => {
// you can add all this logic in pipe(map()) instead of handling in subscribe
console.log(`data returned`, data)
// some appropriate checks here
if (typeof data === 'object' && data.hasOwnProperty('firstObs')) {
if (!this.secondObsReturned) {
// can use rxjs timer here
this.timerHandle = setTimeout(() => {
console.log('Delayed more than 5 seconds');
this.obsSubcription.unsubscribe();
}, 5000)
}
}
else {
// this is the second onservable (which may have come early)
this.secondObsReturned = true;
}
})
}
}
在此处查看示例:https://stackblitz.com/edit/angular-s6wkk2
编辑
因此,我在考虑某种避免更改返回的Observable的方法,于是我想到了CombineLatest
。结合最新的功能是,它第一次会等待两个Observable中的值,此后,即使有任何Observable解析,它也会发出。
要使用此功能,再次有一个约束。例如,您需要知道Observables永远不会返回的特定值,例如false
,因此,如果您知道Observables永远不会返回false
(或任何默认值),则可以使用BehaviorSubjects和CombineLatest。使用永远无法返回的值初始化BehaviorSubjects。
您需要点按可观察对象以为对象添加值。
// give appropriate types
subjectOne = <any> new BehaviorSubject(false); // will contain value of the first observable
subjectTwo = <any> new BehaviorSubject(false); // will contain value of the second observable
takeUntilSub = new Subject(); // use this to stop the subscriptions
obsOne = of('First Obs')
.pipe(
tap((value) => {
this.subjectOne.next(value);
}),
catchError((e) => {
// if an Error occurs in first then you don't want to proceeed at all
// add an error in the subjectOne, this will stop the combineLatest stream.
this.subjectOne.error('Observable one errored')
return throwError;(e)
})
)
obsTwo = of('Second Obs')
.pipe(
delay(6000),
tap((value) => {
this.subjectTwo.next(value);
}),
catchError((e) => {
// if you want to continue the stream, you need to handle the error and return a success.
// no need to populate the subject coz you don't care about this error
return of(e)
})
)
secondObsReturned = false
timerHandle;
ngOnInit() {
// calling the actual Observables here.
merge(this.obsOne, this.obsTwo).pipe(takeUntil(this.takeUntilSub)).subscribe()
// this will be called once for the very first time giving values as false for both of them (or the emitted initial values)
// after that when any one of them resolves, flow will come here
combineLatest(this.subjectOne, this.subjectTwo).pipe(takeUntil(this.takeUntilSub)).subscribe(([dataFromObsOne, dataFromObsTwo]) => {
console.log(`data received: ${dataFromObsOne} and ${dataFromObsTwo}`)
if (dataFromObsTwo !== false) {
// second observable was resolved
this.secondObsReturned = true;
if (this.timerHandle) {
clearTimeout(this.timerHandle);
}
}
if (dataFromObsOne !== false) {
// first observable resoved
if (!this.secondObsReturned) {
// if second obs hasn't already been resolved then start a timer.
this.timerHandle = setTimeout(() => {
console.log('Delayed more than 5 seconds');
this.takeUntilSub.next(true); // stop all subscriptions
}, 5000)
}
}
})
}
在此处查看示例:Code Link。
答案 1 :(得分:-1)
您可以使用forkJoin运算符。当您有多个请求但必须等待第一个请求的响应然后可以触发下一个请求时,将使用此运算符。
有关更多信息,请参见forkJoin运算符的RxJS文档。
以下是我尝试汇总的代码段:
constructor(private http: HttpClient)
this.url1 = 'Url 1';
this.url2 = 'Url 2';
public forkJoinExample(): Observable<any> {
let data_1 = this.http.get(this.url1);
let data_2 = this.http.get(this.url2);
return forkJoin([data1, data2]);
}
要添加等待,可以使用defer运算符。实施defer也应该相当简单。
另一种实现方式可以是以下代码段:
let data_1 = this.http.get(this.url1);
let data_2 = this.http.get(this.url2);
const observableData = Rx.Observable.forkJoin([data1, data2]);
observableData.subscribe(
res => {
// Handle response
},
(err) => {
// Handle Error Scenario
},
() => {
// Executes when all the requests are completed
});
还有另一种处理多个错误块的方法,如果您要添加,我可以添加这些错误块。您可以只分叉单个服务调用,最后订阅最终请求,并在这些单个请求中添加尽可能多的响应和错误块。