Несколько подписок, вложенных в одну подписку - PullRequest
0 голосов
/ 16 октября 2019

Я озадачен попыткой установить очень простой поток подписок rxjs. Наличие нескольких несвязанных подписок, вложенных в другую.

Я нахожусь в угловом приложении, и мне нужно заполнить тему следующим, прежде чем делать другие подписки.

Здесь будет вложенная версиятого, чего я хочу достичь.

subject0.subscribe(a => {

    this.a = a;

    subject1.subscribe(x => {
        // Do some stuff that require this.a to exists
    });

    subject2.subscribe(y => {
        // Do some stuff that require this.a to exists
    });

});

Я знаю, что вложенные подписки не являются хорошей практикой, я пытался использовать flatMap или concatMap, но на самом деле не понял, как это реализовать.

Ответы [ 3 ]

1 голос
/ 16 октября 2019

Вы можете сделать что-то вроде этого:

subject$: Subject<any> = new Subject();
this.subject$.pipe(
        switchMap(() => subject0),
        tap(a => {
            this.a = a;
        }),
        switchMap(() => subject1),
        tap(x => {
            // Do some stuff that require this.a to exists
        }),
        switchMap(() => subject2),
        tap(y => {
            // Do some stuff that require this.a to exists
        })
    );

, если вы хотите вызвать это, просто вызовите this.subject $ .next ();

РЕДАКТИРОВАТЬ: Вот возможный подходс forkJoin этот крик вызывает субъектов параллельно.

subject$: Subject<any> = new Subject();
    this.subject$.pipe(
        switchMap(() => subject0),
        tap(a => {
            this.a = a;
        }),
        switchMap(
            () => forkJoin(
                subject1,
                subject2
        )),
        tap([x,y] => {
          // Do some stuff that require this.a to exists
        })
    );
1 голос
/ 16 октября 2019

Всегда полезно разделять потоки данных по наблюдаемым, чтобы потом их можно было легко объединить.

const first$ = this.http.get('one').pipe(
  shareReplay(1)
)

shareReplay используется для создания наблюдаемой горячей поэтому он не будет вызывать http.get('one') для каждой подписки.

const second$ = this.first$.pipe(
  flatMap(firstCallResult => this.http.post('second', firstCallResult))
);

const third$ = this.first$.pipe(
  flatMap(firstCallResult => this.http.post('third', firstCallResult))
);

После этого вы можете выполнять подписки на Observables, которые вам нужны:

second$.subscribe(()=>{}) // in this case two requests will be sent - the first one (if there were no subscribes before) and the second one

third$.subscribe(() => {}) // only one request is sent - the first$ already has the response cached

Если вы этого не сделаетехотите хранить значение first$ в любом месте, просто преобразуйте его в:

this.http.get('one').pipe(
  flatMap(firstCallResult => combineLatest([
    this.http.post('two', firstCallResult),
    this.http.post('three', firstCallResult)
  ])
).subscribe(([secondCallResult, thirdCallResult]) => {})

Также вы можете использовать BehaviorSubject, в котором хранится значение:

const behaviorSubject = new BehaviorSubject<string>(null); // using BehaviorSubject does not require you to subscribe to it (because it's a hot Observable)
const first$ = behaviorSubject.pipe(
  filter(Boolean), // to avoid emitting null at the beginning
  flatMap(subjectValue => this.http.get('one?' + subjectValue))
)

const second$ = first$.pipe(
  flatMap(firstRes => this.http.post('two', firstRes))
)

const third$ = first$.pipe(
  flatMap(()=>{...})
)

behaviorSubject.next('1') // second$ and third$ will emit new values
behaviorSubject.next('2') // second$ and third$ will emit the updated values again
1 голос
/ 16 октября 2019

Это можно сделать с помощью оператора concat.

const first = of('first').pipe(tap((value) => { /* doSomething */ }));
const second = of('second').pipe(tap((value) => { /* doSomething */ }));
const third = of('third').pipe(tap((value) => { /* doSomething */ }));

concat(first, second, third).subscribe();

Таким образом, все цепочки и выполняются в том же порядке, как определено.

РЕДАКТИРОВАТЬ

const first = of('first').pipe(tap(value => {
  // doSomething
  combineLatest(second, third).subscribe();
}));
const second = of('second').pipe(tap(value => { /* doSomething */ }));
const third = of('third').pipe(tap(value => { /* doSomething */ }));
first.subscribe();

Таким образом, second и third работают асинхронно, как только выдается first.

...