concatMap()等效,但在mergeMap()中是异步的

时间:2017-10-10 09:07:51

标签: rxjs observable

我有一个可观察的myObservable

let myObservable = Observable.of(2000, 1000)

使用concatMap():TOTAL TIME = 3000 millis,产生原始订单。

myObservable.concatMap(v => Rx.Observable.of(v).delay(v))
// concatMap: 2000, concatMap: 1000

使用mergeMap():TOTAL TIME = 2000 millis,结果不是原始顺序。

myObservable.mergeMap(v => Rx.Observable.of(v).delay(v))
// mergeMap: 1000, mergeMap: 2000

我希望有一种方法可以像concatMap一样以原始顺序获取结果,但是异步调用每个嵌套的observable而不是等待下一个嵌套的observable完成:

// --- The behavior that I want ---
myObservable.myCustomMap(v => Rx.Observable.of(v).delay(v))
// myCustomMap: 2000, myCustomMap: 1000
// TOTAL TIME = 2000 millis

有优雅的解决方案吗?

编辑:我正在寻找一种解决方案,如果源(myObservable)是异步的,它也可以正常工作,不仅适用于这种特殊的同步情况。

2 个答案:

答案 0 :(得分:1)

您应该使用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秒钟(当它们同时被触发时,它们的最大值)

工作Plunkr: https://plnkr.co/edit/IRgEhdjCmZSTc6hSaVeF?p=preview

修改1:感谢@PierreCitror指出toArray优于scan:)

答案 1 :(得分:1)

我会这样做:

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中,您可以编写您想要的任何逻辑,以决定当前状态是否应该进一步传播(例如,您可以等到一定数量的响应到达或等等)。