RxJs中按属性区分的switchMap

时间:2019-07-06 20:05:36

标签: javascript rxjs ngrx redux-observable switchmap

比方说,我有一系列行动。每个动作都分配了一些ID。像这样:

const actions$ = of({ id: 1 }, { id: 2 }, { id: 1 });

现在,对于每个动作,我想在switchMap中执行一些逻辑:

actions$.pipe(switchMap(a => /* some cancellable logic */)).subscribe(...);

问题在于,每个发出的动作都会取消先前的“某些可取消的逻辑”。

是否可以根据操作 id (最好是操作员)取消“某些可取消的逻辑”?像这样:

actions$.pipe(switchMapBy('id', a => /*some cancellable logic */)).subscribe(...)

本质上说,当前行为与 switchMap
1. actions $ 发出ID#1。 switchMap 订阅嵌套的Observable。
2. actions $ 发出ID#2。 switchMap 取消订阅先前嵌套的Observable。订阅新的。
3. actions $ 发出ID#1。 switchMap 再次取消订阅先前嵌套的Observable。订阅新的。

预期的行为
1. actions $ 发出ID#1。 switchMap 订阅嵌套的Observable。
2. actions $ 发出ID#2。 switchMap 再次订阅嵌套的observable(这次是#2)。 这是区别,它不会取消#1中的那个。

3. actions $ 发出ID#1。 switchMap 取消订阅可观察的#1嵌套。再次订阅#1。

2 个答案:

答案 0 :(得分:3)

这似乎是mergeMap运算符的用例。 switchMap的用例是仅维护一个内部订阅并取消先前的订阅,这不是您要遵循的。您需要多个内部订阅,并且希望它们在具有相同id的新值通过时取消,因此请实施一些自定义逻辑来实现。

类似的东西:

action$.pipe(
  mergeMap(val => {
    return (/* your transform logic here */)
              .pipe(takeUntil(action$.pipe(filter(a => a.id === val.id)))); // cancel it when the same id comes back through, put this operator at the correct point in the chain
  })
)

您可以通过编写自定义运算符将其转换为可重用的内容:

import { OperatorFunction, Observable } from 'rxjs';
import { takeUntil, filter, mergeMap } from 'rxjs/operators';

export function switchMapBy<T, R>(key: keyof T, mapFn: (val: T) => Observable<R>): OperatorFunction<T, R> {
  return input$ => input$.pipe(
    mergeMap(val => 
      mapFn(val).pipe(
        takeUntil(input$.pipe(filter(i => i[key] === val[key])))
      )
    )
  );
}

并像这样使用它:

action$.pipe(
  switchMapBy('id', (val) => /* your transform logic here */)
);

在行动中突如其来:https://stackblitz.com/edit/rxjs-x1g4vc?file=index.ts

答案 1 :(得分:0)

在switchMap之前

使用 filter 操作以排除已取消的ID,例如

of({ id: 1 }, { id: 2 }, { id: 1 }).pipe(
   filter(id => ![1,2].includes(id)), // to exclude ids (1,2)
   switchMap(id => /*some cancellable logic */ )
).subscribe(...)