[英]Chaining more than two Angular Observable calls
I'm currently working on an Angular 5 service, and I need to chain four separate Observable calls, with each subsequent call using the data from some or all previous calls . 我目前正在使用Angular 5服务,并且需要链接四个单独的Observable调用,每个后续调用都使用部分或全部先前调用中的数据。 I've seen some examples of combining two calls, but I don't see how to use more than two (and trying to extend them, via
flatMap
, has resulted in the data from previous calls not being available in subsequent calls). 我已经看到了合并两个调用的一些示例,但是我看不到如何使用两个以上的示例(尝试通过
flatMap
扩展它们导致先前调用中的数据在后续调用中不可用)。
CallOne
returns Observable<Foo[]>
CallOne
返回Observable<Foo[]>
Foo
Foo
CallTwo
requires a Foo
and returns Observable<FooTwo[]>
CallTwo
需要Foo
并返回Observable<FooTwo[]>
FooTwo
FooTwo
CallThree
requires a FooTwo
and returns Observable<FooThree[]>
CallThree
需要一个FooTwo
并返回Observable<FooThree[]>
FooThree
FooThree
CallFour
requires a Foo
, a FooTwo
, and a FooThree
and returns Observable<Bar[]>
CallFour
需要Foo
, FooTwo
和FooThree
并返回Observable<Bar[]>
Afterwards, I need access to the chosen Foo
, FooTwo
, FooThree
and a specific Bar
. 之后,我需要访问选择的
Foo
, FooTwo
, FooThree
和特定的Bar
。
You can use mergeMap
and forkJoin
, with forkJoin you can fire parallel request at time and it will till all request completed. 您可以使用
mergeMap
和forkJoin
,使用forkJoin可以同时触发并行请求,直到所有请求完成为止。
Observable.forkJoin(
call1(params),
call2(params),
call3(params)
).subscribe((responses) => {
// responses[0] -> response of call1
// responses[1] -> response of call2
// responses[2] -> response of call3
})
However if you want to make it synchronous and make the request dependent on the previous call, you can do like this, 但是,如果您想使其同步并使其请求依赖于上一个调用,则可以这样做,
const request1$ = Rx.Observable.of('response1').delay(2000);
const request2$ = Rx.Observable.of('response2').delay(100);
Rx.Observable.forkJoin(request1$, request2$)
.subscribe(res => console.log(`forkJoin: ${res}`));
CallOne
returns Observable<Foo[]>
CallOne
返回Observable<Foo[]>
Foo
Foo
CallTwo
requires a Foo
and returns Observable<FooTwo[]>
CallTwo
需要Foo
并返回Observable<FooTwo[]>
FooTwo
FooTwo
CallThree
requires a FooTwo
and returns Observable<FooThree[]>
CallThree
需要一个FooTwo
并返回Observable<FooThree[]>
FooThree
FooThree
CallFour
requires a Foo
, a FooTwo
, and a FooThree
and returns Observable<Bar[]>
CallFour
需要Foo
, FooTwo
和FooThree
并返回Observable<Bar[]>
Based on the above spec: 根据以上规格:
callOne().pipe(
switchMap((foos: Foo[]) => {
// filtering foos to get Foo
this.Foo = <filtered_foo>;
return callTwo(<filtered_foo>);
}),
switchMap((foos2: FooTwo[]) => {
// filtering foos2 to get FooTwo
this.FooTwo = <filtered_foo_two>;
return callThree(<filtered_foo_two>);
}),
switchMap((foos3: FooThree[]) => {
// filtering foos3 to get FooThree
this.FooThree= <filtered_foo_three>;
return callFour(this.Foo, this.FooTwo, <filtered_foo_three>);
})
).subscribe((bars: Bar[]) => {
this.bars = bars;
/**
* this.Foo, this.FooTwo, this.FooThree and this.bars will all be available here
*/
})
I'm not sure if this is the most efficient way to solve this, but this is what worked for me: 我不确定这是否是解决此问题的最有效方法,但这对我有用:
return this.callOne()
.flatMap(foo => {
// foo filter logic here
return this.callTwo(foo[0].id).map(fooTwo => ({ foo, fooTwo }));
})
.flatMap(({ foo, fooTwo }) => {
// fooTwo filter logic here
return this.callThree(fooTwo[0].id).map(fooThree => ({ foo, fooTwo, fooThree }));
})
.flatMap(({ foo, fooTwo, fooThree }) => {
return this.callFour(fooTwo[0].id, fooThree[0]).map(bar => ({ foo, fooTwo, fooThree, bar }));
})
.do(({ foo, fooTwo, fooThree, bar }) => {
// additional processing here
return ({ foo, fooTwo, fooThree, bar });
});
Since you have so many values you need to keep track of, I would really suggest you use Subject
. 由于您需要跟踪许多值,因此我建议您使用
Subject
。 That is the exact purpose of Subject
- to retain the values. 那是
Subject
的确切目的-保留值。 In your case for example you can use BehaviourSubject
. 例如,您可以使用
BehaviourSubject
。
First, declare the subject needed: 首先,声明所需的主题:
let call1Subject = new BehaviourSubject<Foo[]>(null);
let call2Subject = new BehaviourSubject<FooTwo[]>(null);
let call3Subject = new BehaviourSubject<FooThree[]>(null);
Now, you can update the values of the BehaviourSubject
using .next
, and you can get its most current value via .value()
: 现在,您可以使用
.next
更新BehaviourSubject
的值,并可以通过.value()
获得其最新值:
return this.callOne()
.flatMap(foo => {
// foo filter logic here
call1Subject.next(foo);
return this.callTwo(foo[0].id);
})
.flatMap(fooTwo => {
// fooTwo filter logic here
call2Subject.next(fooTwo);
return this.callThree(fooTwo[0].id);
})
.flatMap(fooThree => {
call3Subject.next(fooThree);
let fooTwo = call2Subject.value();
return this.callFour(fooTwo[0].id, fooThree[0]);
})
.map(bar => {
// additional processing here
let foo = call1Subject.value();
let fooTwo = call2Subject.value();
let fooThree = call3Subject.value();
return ({foo, fooTwo, fooThree, bar});
});
The code looks much much neater, and you have a very clear context. 该代码看起来更加整洁,并且您具有非常清晰的上下文。 The
.map()
way works too; .map()
方法也可以工作; but your code can easily get bloated and its harder to manage. 但是您的代码很容易变得肿并且难以管理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.