网站搜索

typescript - Angular/RxJS - 有没有用于流开始的 RxJS pipe?


我正在尝试创建一种方法,在处理某些流时动态显示和隐藏加载屏幕。

这是我目前的代码:

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 管道正确吗?有其他管道可以更好地解决这个问题吗?

使用 RxJS 做这件事的最佳方式是什么?

答案#1

在你的第一个例子中,当你的 HTTP 请求完成后,你的 tap 才会运行。

最终,你只需在开始 HTTP 请求之前调用 this.startLoading()。

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

});

如果你 真的 想在管道中调用 this.startLoading(),你可以在 HTTP 请求开始之前调用它,通过从你自己的 Observable 开始:

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

});

但是那样做其实并没有太大意义。

所以你的 tap 语法是正确的,只是它没有在你认为它应该执行的时候执行。

答案#2

如果你想在每个可观察对象的订阅上执行副作用,你可以使用 defer() 包装源。

import { defer } from 'rxjs';

...

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