链接两个以上的 Angular 可观察调用



我目前正在研究 Angular 5 服务,我需要链接四个单独的 Observable 调用,每个后续调用都使用来自之前部分或所有调用的数据。我已经看到了一些组合两个调用的示例,但我看不到如何使用两个以上的调用(并且尝试通过flatMap扩展它们会导致以前调用的数据在后续调用中不可用(。

  • CallOne返回Observable<Foo[]>
    • 然后,我需要进行一些过滤以选择特定的Foo
  • CallTwo需要Foo并返回Observable<FooTwo[]>
    • 然后,我需要进行一些过滤以选择特定的FooTwo
  • CallThree需要FooTwo并返回Observable<FooThree[]>
    • 然后,我需要进行一些过滤以选择特定的FooThree
  • CallFour需要FooFooTwoFooThree,并返回Observable<Bar[]>

之后,我需要访问所选FooFooTwoFooThree和特定Bar

您可以使用mergeMapforkJoin,使用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
})

但是,如果要使其同步并使请求依赖于上一个调用,则可以这样做,

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}`));

处理相互依赖的可观察量

我不确定这是否是解决此问题的最有效方法,但这就是对我有用的方法:

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 });
});

由于您需要跟踪的值太多,我真的建议您使用Subject.这就是Subject的确切目的——保留价值观。例如,在您的情况下,您可以使用BehaviourSubject.

首先,声明所需的主题:

let call1Subject = new BehaviourSubject<Foo[]>(null);
let call2Subject = new BehaviourSubject<FooTwo[]>(null);
let call3Subject = new BehaviourSubject<FooThree[]>(null);

现在,您可以使用.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});
});

代码看起来更整洁,并且您有一个非常清晰的上下文。.map()方式也有效;但是您的代码很容易变得臃肿,并且更难管理。

  • CallOne返回Observable<Foo[]>
    • 然后,我需要进行一些过滤以选择特定Foo
  • CallTwo需要Foo并返回Observable<FooTwo[]>
    • 然后,我需要进行一些过滤以选择特定FooTwo
  • CallThree需要FooTwo并返回Observable<FooThree[]>
    • 然后,我需要进行一些过滤以选择特定FooThree
  • CallFour需要FooFooTwoFooThree,并返回Observable<Bar[]>

基于上述规范:

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
*/
})

最新更新