簡體   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