Angular / Rx JS - Существует канал Rx JS для запуска потока? - PullRequest
1 голос
/ 05 марта 2020

Я пытаюсь создать способ динамически представлять и скрывать экран загрузки при разрешении некоторого потока.

Вот мой текущий код:

this.requestService
        .get<Checkout>(`check/${orderNumber}`)
        .pipe(
            tap(() => this.startLoading()),  //i think this isnt the right way to use this pipe
            finalize(() => this.endLoading())
        )
        .subscribe(
            data => {
                data.orderNumber = orderNumber
                this.checkout.next(data)
            },
            error => {
                this.notification.warning(error)
            }
        )

Ожидаемый результат - это когда мой поток запускается , чтобы экран загрузки отображался с startLoading(), когда операция завершена, скрыть загрузку, используя endLoading().

Мой рабочий код:

this.startLoading() //basically calling function before i create the stream

this.requestService
        .get<Checkout>(`check/${orderNumber}`)
        .pipe(                
            finalize(() => this.endLoading())
        )
        .subscribe(
            data => {
                data.orderNumber = orderNumber
                this.checkout.next(data)
            },
            error => {
                this.notification.warning(error)
            }
        )

Я правильно использую эту трубу tap? Есть ли другой канал, чтобы лучше решить эту проблему?

Каков наилучший способ сделать это, используя Rx JS?

Ответы [ 3 ]

1 голос
/ 05 марта 2020

Если вы хотите выполнять побочные эффекты для каждой наблюдаемой подписки, вы можете деформировать источник с помощью defer().

import { defer } from 'rxjs';

...

defer(() => {
  this.startLoading();
  return this.requestService.get<Checkout>(`check/${orderNumber}`);
}).pipe(
    finalize(() => this.endLoading())
  )
  .subscribe(...);
1 голос
/ 07 марта 2020

Вы можете использовать BehaviorSubject и Rx Js defer с трубой finalize для отслеживания процесса загрузки.

import { defer } from 'rxjs';

// ...

public this.loading: BehaviorSubject<boolean> = new BehaviorSubject(false);

// ...

public getOrder(orderNumber): Observable<Checkout> {
  defer(() => {
    this.loading.next(true);
    return this.requestService.get<Checkout>(`check/${orderNumber}`);
  }).pipe(
    finalize(() => this.loading.next(false)
  );
}

// to get boolean from BehaviorSubject -> is loading
public isLoading(): boolean {
  return this.loading.value;
}

// ...

Теперь вы также можете использовать this.loading наблюдаемый за пределами вашего класса, например, чтобы показать или скрыть загрузчик на основе наблюдаемого значения:

// logs to console each time loading state changes
serviceName.loading.subscribe(result => console.log(result));

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

1 голос
/ 05 марта 2020

В первом примере ваш касание запускается после того, как ваш http-запрос завершен.

В конечном счете, вы просто позвоните this.startLoading(), прежде чем запустить http-запрос.

this.startLoading();
this.requestService.get<Checkout>(`check/${orderNumber}`).pipe(
  finalize(() => this.endLoading())
).subscribe(() => {

});

Если вы действительно хотите вызвать this.startLoading() в канале, который вы могли бы вызвать до того, как запрос http начнется, начиная с вашей собственной наблюдаемой:

return of(null).pipe(
  tap(() => this.startLoading()),
  concatMap(() => this.requestService.get<Checkout>(`check/${orderNumber}`)),
  finalize(() => this.endLoading())
).subscribe(() => {

});

Но тогда нет особого смысла при этом.

Так что ваш синтаксис tap правильный, он просто не выполняется, когда вы думаете, что это должно быть.

...