繁体   English   中英

仅针对 Observable 的某些发射执行 rxjs 管道的一部分

[英]Do parts of an rxjs pipe only for certain emissions of the Observable

我有一个我订阅的 rxjs-Observable。 我现在有两种不同的需要在 Observable 的管道内处理。

首先我想映射输出。 其次,我想使用tap来触发副作用,但不能在第一次发射时触发副作用。

所以这显然不起作用,因为skip在管道上全局工作:

this.userChangeSubscription = this.userStateService.userState$
  .pipe(
    map(userState => userState.prop),
    skip(1),
    tap(() => this.sideEffect())
   )
  .subscribe();

有没有办法做到这一点,而无需订阅 Observable 两次?

编辑:好的,我现在有几个似乎都有效的选项。 现在:选择哪一个?

我已经看到已经有有效的答案,但我认为最好的办法是为此用例编写自己的 rxjs 运算符。 这会产生一个干净的解决方案,并且在您的pipe函数中阐明了您的意图。

为此,我们需要使用defer observable

function tapSkipFirst<T>(fn: Function): OperatorFunction<T, T> {
  return function(source: Observable<any>) {
    return defer(() => {
      let skip = true;
      return source.pipe(
        tap((v?:any) => {
          if (!skip) {
            fn(v);
          }
          skip = false;
        })
      );
    });
  };
}

我们使用skip变量来决定是否运行副作用函数。 在第一次运行结束时,我们将skip切换为 false,因此为所有后续运行运行副作用函数。 我们需要在这里使用defer observable,因为defer的代码只在订阅时调用,而不是在创建时调用。 这很重要,否则所有订阅都将共享相同的skip变量。

现在您可以轻松使用新的自定义运算符,例如:

this.userChangeSubscription = this.userStateService.userState$
  .pipe(
    map(userState => userState.prop),
    tapSkipFirst(() => this.sideEffect())
   )
  .subscribe();

对的,这是可能的。 例子:

const userProp$ = this.userStateService.userState$.pipe(
  map(userState => userState.prop),
  shareReplay({ bufferSize: 1, refCount: true })
);

在这里 shareReplay 将让您在多个订阅者之间共享该资源,而无需再次触发整个链。 一旦所有订阅者都收听完毕,shareReplay 将结束,上面的 observable 也将结束。

然后,您可以根据需要多次订阅,并隔离副作用,这首先是一个好主意:

userProp$
  .pipe(
    skip(1),
    tap(() => this.sideEffect())
  )
  .subscribe();

您可以将switchMap运算符用于此类用例。 它为您提供了一个index参数,允许您根据第一个、第二个、第三个等发射来执行不同的操作。

在这种情况下,如果index等于 0(第一次排放),则sideEffect不会被触发,但会因任何其他期货排放而被触发。

我使用此运算符来触发副作用或根据条件更改发出的值。 这很棒,因为您不需要将源 Observable 拆分为具有不同管道的两个不同 Observable。

this.userChangeSubscription = this.userStateService.userState$
  .pipe(
    map(userState => userState.prop),
    switchMap((value, index) => {
      return index > 0
        ? of(value).pipe(tap(() => this.sideEffect()))
        : of(value);
    })
  )
.subscribe();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM