链接两个以上的Angular Observable调用

时间:2018-05-29 19:06:03

标签: angular rxjs

我目前正在开发Angular 5服务,我需要链接四个单独的Observable调用,每次后续调用都使用来自部分或全部之前调用的数据。我已经看到了一些组合两个调用的示例,但是我没有看到如何使用两个以上(并尝试通过flatMap扩展它们)导致以前调用的数据在后续无法使用呼叫)。

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

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

4 个答案:

答案 0 :(得分:0)

您可以使用 mergeMap forkJoin ,使用forkJoin,您可以及时触发并行请求,直到所有请求都完成。< / p>

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

Handling Observables that depend on each other

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

由于你需要跟踪这么多的值,我建议你使用Subject。这是Subject的确切目的 - 保留价值。例如,您可以使用BehaviourSubject

首先,宣布所需的主题:

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

现在,您可以使用BehaviourSubject更新.next的值,并且可以通过.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()方式也有效;但是你的代码很容易变得臃肿而且难以管理。