Javascript RxJs中按属性区分的开关映射

Javascript RxJs中按属性区分的开关映射,javascript,rxjs,ngrx,redux-observable,switchmap,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(最好是操作员)取消“某些可

比方说,我有一连串的行动。每个操作都分配了一些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.动作$emits id 1。switchMap订阅嵌套的observable。 2.动作$emits id 2。switchMap取消订阅以前嵌套的observable。订阅新的。 3.动作$emits id 1。switchMap再次取消订阅以前嵌套的observable。订阅新的

预期行为: 1.动作$emits id 1。switchMap订阅嵌套的observable。 2.动作$emits id 2。switchMap再次订阅嵌套的observable,这次是2。这里的区别是,它不会抵消1中的一个。 3.动作$emits id 1。switchMap从嵌套的observable取消订阅1。再次订阅,例如1。

在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(...)
在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(...)

这似乎是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 } from 'rxjs';
import { takeUntil, filter, mergeMap } from 'rxjs/operators';

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

下面是一个闪电战:这似乎是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 } from 'rxjs';
import { takeUntil, filter, mergeMap } from 'rxjs/operators';

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

这里有一个闪电战:你想要的是什么还不清楚,我会尝试添加一些你正在寻找的行为的具体例子。我最好学画大理石图。现在清楚多了。看起来你更喜欢合并地图,我不确定。当第二次发出id为1的操作时,mergeMap不会取消上一个操作。您需要一些自定义逻辑来取消其他订阅,它不会自动执行此操作,尝试提出解决方案时,mergeScan可能更适合这种情况。您要做的是相当不清楚,我会尝试添加一些你正在寻找的行为的具体例子。我最好学画大理石图。现在清楚多了。看起来你更喜欢合并地图,我不确定。当第二次发出id为1的操作时,mergeMap不会取消上一个操作。您需要一些自定义逻辑来取消其他订阅,它不会自动执行,试图找到解决方案,mergeScan可能更适合这种情况。谢谢!这就是我需要的。我想我将把它隐藏在自定义操作符后面,因为它将在几个地方使用。我添加了一个示例,说明如何将我的解决方案转换为可恢复的自定义switchMapBy操作符库!这就是我需要的。我想我将把它隐藏在自定义操作符后面,因为它将在几个地方使用。我添加了一个示例,说明如何将我的解决方案转换为可恢复的自定义switchMapBy操作符