Цепочка более двух угловых наблюдаемых вызовов - PullRequest
0 голосов
/ 29 мая 2018

В настоящее время я работаю над службой Angular 5, и мне нужно объединить четыре отдельных вызова в Observable, при этом каждый последующий вызов использует данные из некоторых или всех предыдущих вызовов .Я видел несколько примеров объединения двух вызовов, но я не вижу, как использовать более двух вызовов (и попытка расширить их с помощью flatMap привела к тому, что данные предыдущих вызовов не были доступны при последующих вызовах).

  • CallOne возвращает Observable<Foo[]>
    • Затем мне нужно выполнить некоторую фильтрацию, чтобы выбрать конкретный Foo
  • CallTwo требует Foo и возвращает Observable<FooTwo[]>
    • Затем мне нужно выполнить некоторую фильтрацию, чтобы выбрать конкретный FooTwo
  • CallThree Требуется FooTwo и возвращает Observable<FooThree[]>
    • Затем мне нужно выполнить некоторую фильтрацию, чтобы выбрать конкретный FooThree
  • CallFour требует Foo, a FooTwo, а FooThree и возвращает Observable<Bar[]>

После этого мне нужен доступ к выбранным Foo, FooTwo, FooThree и конкретному Bar.

Ответы [ 4 ]

0 голосов
/ 30 мая 2018

Поскольку у вас так много значений, которые необходимо отслеживать, я бы действительно рекомендовал вам использовать 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() тоже работает;но ваш код может легко раздуться и его сложнее управлять.

0 голосов
/ 29 мая 2018
  • CallOne возвращает Observable<Foo[]>
    • Затем мне нужно выполнить некоторую фильтрацию, чтобы выбрать конкретный Foo
  • CallTwo требуетсяFoo и возвращает Observable<FooTwo[]>
    • Затем мне нужно выполнить некоторую фильтрацию, чтобы выбрать конкретный FooTwo
  • CallThree, требующий FooTwo и возвратObservable<FooThree[]>
    • Затем мне нужно выполнить некоторую фильтрацию, чтобы выбрать конкретный FooThree
  • CallFour, требующий Foo, FooTwo иa FooThree и возвращает 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
     */
})
0 голосов
/ 29 мая 2018

Я не уверен, что это самый эффективный способ решить эту проблему, но вот что сработало для меня:

 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 });
  });
0 голосов
/ 29 мая 2018

Вы можете использовать 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
})

Однако, если вы хотите сделать его синхронным и сделать запрос зависимым от предыдущего вызова, вы можете сделать это следующим образом:

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

Обработка наблюдаемых, которые зависят друг от друга

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...