【问题标题】:RxJS - Conditionally add observable in a pipeRxJS - 有条件地在管道中添加 observable
【发布时间】:2021-01-13 15:01:36
【问题描述】:

所以我有一个像下面这样的功能

showLoader = () => <T>(source: Observable<T>) => {
  LoaderService.loadPage.next(true);
  return source.pipe(
    finalize(() => {
        LoaderService.loadPage.next(false);
    })
  );
};

然后我在进行如下 HTTP 调用时使用它

return this.http.get(url).pipe(showLoader())

但是假设我遇到了一个场景,我需要加载器或任何基于条件的 observable;像下面的东西

const loader : boolean = false
return this.http.get(url).pipe(concat(...), loader ? showLoader() : of(values))

我尝试使用iif 运算符,如下所示

const loader : boolean = false
    return this.http.get(url).pipe(concat(...), mergeMap(v => iif(() => loader, showLoader(), of(v))))

并得到以下错误

TS2345:“(来源:Observable)=> Observable”类型的参数 不可分配给“SubscribableOrPromise”类型的参数。

有人能帮我理解我哪里出了问题以及如何纠正问题

【问题讨论】:

    标签: javascript angularjs typescript rxjs


    【解决方案1】:

    我建议如下:

    const startWithTap = (callback: () => void) =>
      <T>(source: Observable<T>) => of({}).pipe(
        startWith(callback),
        switchMap(() => source)
      );
    
    const showLoader = () => <T>(source: Observable<T>) => concat(
      iif(
        () => loader,
        source.pipe(
          startWithTap(() => LoaderService.loadPage.next(true)),
          finalize(() => {
            LoaderService.loadPage.next(false);
          })
        ),
        EMPTY
      ), source);
    
    return this.http.get(url).pipe(
      showLoader()
    );
    

    【讨论】:

    • 我们在很多地方都使用了 showLoader 函数,因此我们需要更改所有管道以传递源代码。有没有办法显式传递源代码?
    • 你应该使用 defer 而不是 startWithTap 函数。
    • 感谢@GogaKoreli 的帮助
    【解决方案2】:

    你可以这样做:

    showLoader = (show: boolean = true) => <T>(source: Observable<T>) => {
      if (!show) { // just go straight to source
        return source;
      }
    
      return defer(() => { // defer makes sure you don't show the loader till actually subscribed
        LoaderService.loadPage.next(true);
        return source.pipe(
          finalize(() => {
            LoaderService.loadPage.next(false);
          })
        )
      })
    };
    

    使用:

    return this.http.get(url).pipe(showLoader(false))
    

    但是您似乎静态访问LoaderService 的方式在您的未来充满了设计问题和错误。仅供参考。

    【讨论】:

    • 这实际上比我的回答要好
    • @bryan60 loaderService 使用 DI 并注入到构造函数中。或者,如果您建议为此使用 Httpinterceptor?如果不是问题,您能简单介绍一下设计问题吗?
    • 设计问题是您似乎使用 LoaderService 静态方法具有此功能。您不应该使用静态方法。当您在 DI 框架之外这样做时,它们会导致问题。
    • 非常感谢@bryan60。它就在我眼前,我没有注意到。将进行更改:)
    猜你喜欢
    • 1970-01-01
    • 2017-03-09
    • 1970-01-01
    • 1970-01-01
    • 2021-06-05
    • 2020-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多