Rxjs concatMap()等效,但与mergeMap()中的异步类似

Rxjs concatMap()等效,但与mergeMap()中的异步类似,rxjs,observable,Rxjs,Observable,我有一个可观察的myObservable: let myObservable = Observable.of(2000, 1000) 使用concatMap():总时间=3000毫秒,结果为原始顺序 myObservable.concatMap(v => Rx.Observable.of(v).delay(v)) // concatMap: 2000, concatMap: 1000 myObservable.mergeMap(v => Rx.Observable.of(v).d

我有一个可观察的
myObservable

let myObservable = Observable.of(2000, 1000)
使用
concatMap()
:总时间=3000毫秒,结果为原始顺序

myObservable.concatMap(v => Rx.Observable.of(v).delay(v))
// concatMap: 2000, concatMap: 1000
myObservable.mergeMap(v => Rx.Observable.of(v).delay(v))
// mergeMap: 1000, mergeMap: 2000
使用
mergeMap()
:总时间=2000毫秒,结果不符合原始顺序

myObservable.concatMap(v => Rx.Observable.of(v).delay(v))
// concatMap: 2000, concatMap: 1000
myObservable.mergeMap(v => Rx.Observable.of(v).delay(v))
// mergeMap: 1000, mergeMap: 2000
我想要一种方法,以原始顺序获得结果,如
concatMap
,但异步调用每个嵌套的可观察对象,而不是等待下一个嵌套的可观察对象完成:

// --- The behavior that I want ---
myObservable.myCustomMap(v => Rx.Observable.of(v).delay(v))
// myCustomMap: 2000, myCustomMap: 1000
// TOTAL TIME = 2000 millis
有优雅的解决方案吗


编辑:我正在寻找一种在源(
myObservable
)是异步的情况下也能工作的解决方案,而不仅仅是在这个特定的同步情况下。

您应该使用
forkJoin
同时触发所有可观察对象

下面是一个没有注释的示例:

const { Observable } = Rx;

const obs$ = Observable
  .of(3000, 3000, 1000)
  .map(x => Observable.of(x).delay(x));

const allObsWithDelay$ = obs$.toArray();

const result$ = allObsWithDelay$
  .switchMap(arr => Observable.forkJoin(arr));

result$
  .do(console.log)
  .subscribe();
解释也是如此:

const { Observable } = Rx;

// source observable, emitting simple values...
const obs$ = Observable
  .of(3000, 3000, 1000)
  // ... which are wrapped into a different observable and delayed
  .map(x => Observable.of(x).delay(x));

// use a reduce to build an array containing all the observables
const allObsWithDelay$ = obs$.toArray();

const result$ = allObsWithDelay$
  // when we receive the array with all the observable
  // (so we get one event, with an array of multiple observables)
  .switchMap(arr =>

    // launch every observable into this array at the same time
    Observable.forkJoin(arr)
  );

// display the result
result$
  .do(console.log)
  .subscribe();
使用这些值:
3000、3000、1000
整个过程需要3秒(最大值为同时启动时的时间)

工作负载:KR:


编辑1:感谢您指出
toArray
优于
scan
:)

您应该使用
forkJoin
同时触发所有可观察对象

下面是一个没有注释的示例:

const { Observable } = Rx;

const obs$ = Observable
  .of(3000, 3000, 1000)
  .map(x => Observable.of(x).delay(x));

const allObsWithDelay$ = obs$.toArray();

const result$ = allObsWithDelay$
  .switchMap(arr => Observable.forkJoin(arr));

result$
  .do(console.log)
  .subscribe();
解释也是如此:

const { Observable } = Rx;

// source observable, emitting simple values...
const obs$ = Observable
  .of(3000, 3000, 1000)
  // ... which are wrapped into a different observable and delayed
  .map(x => Observable.of(x).delay(x));

// use a reduce to build an array containing all the observables
const allObsWithDelay$ = obs$.toArray();

const result$ = allObsWithDelay$
  // when we receive the array with all the observable
  // (so we get one event, with an array of multiple observables)
  .switchMap(arr =>

    // launch every observable into this array at the same time
    Observable.forkJoin(arr)
  );

// display the result
result$
  .do(console.log)
  .subscribe();
使用这些值:
3000、3000、1000
整个过程需要3秒(最大值为同时启动时的时间)

工作负载:KR:


编辑1:感谢您指出
toArray
scan
:)更好。

我会这样做:

myObservable
  .mergeMap((val, i) => Observable.forkJoin(
    Observable.of(i),
    Observable.of(v).delay(v)
  ))
  .scan((acc, ([i, result])) => {
    acc[i] = result;
    return acc;
  }, {})
  .filter(allResults => {
    // Whatever goes here
    Object.keys(allResults) // list indices of all finished responses 
  })
这将在单个对象中累积所有响应,其中每个响应都被分配一个索引,在该索引处它到达
mergeMap


然后在
filter
中,您可以编写任何逻辑来决定当前状态是否应该进一步传播(例如,您可以等待一定数量的响应或其他任何内容)。

我会这样做:

myObservable
  .mergeMap((val, i) => Observable.forkJoin(
    Observable.of(i),
    Observable.of(v).delay(v)
  ))
  .scan((acc, ([i, result])) => {
    acc[i] = result;
    return acc;
  }, {})
  .filter(allResults => {
    // Whatever goes here
    Object.keys(allResults) // list indices of all finished responses 
  })
这将在单个对象中累积所有响应,其中每个响应都被分配一个索引,在该索引处它到达
mergeMap


然后在
filter
中,您可以编写您想要的任何逻辑,以决定当前状态是否应该进一步传播(例如,您可以等待一定数量的响应或其他任何内容)。

您应该使用
forkJoin
进行此操作。正在编写正确的答案。是否希望源
myObservable
异步发出?我的意思是,用例比可观察的更复杂。of(2000,1000)?@martin是的,用例更复杂,并且可能是异步的。为此,您应该使用
forkJoin
。正在编写正确的答案。是否希望源
myObservable
异步发出?我的意思是,用例比可观察的更复杂。of(2000,1000)?@martin是的,用例更复杂,并且可能是异步的nice Maxime,你可以通过调用toArray()而不是teadriiiiiiiiiilight来简化reduce。这是我一直在寻找但不记得的,thx@perriercitor:DWell,我不确定这正是OP想要的。如果
obs$
是异步的,则
switchMap
将使所有可观察对象取消订阅并再次订阅。例如,当您有5个远程呼叫并且
obs$
发出第6个远程呼叫时,之前的5个都将重复。实际上,在我的用例中,这个解决方案实际上不起作用。我想用一个简单的例子来清楚地解释我的问题,但它把我的问题简化了。欢迎您带来一个更通用的解决方案@martinNice Maxime,您可以通过调用toArray()来简化reduce,而不是Steadriiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii。如果
obs$
是异步的,则
switchMap
将使所有可观察对象取消订阅并再次订阅。例如,当您有5个远程呼叫并且
obs$
发出第6个远程呼叫时,之前的5个都将重复。实际上,在我的用例中,这个解决方案实际上不起作用。我想用一个简单的例子来清楚地解释我的问题,但它把我的问题简化了。欢迎您带来更通用的解决方案@martin