flatMap, mergeMap, switchMap and concatMap in rxjs?

后端 未结 6 475

Someone, please explain the difference between SwitchMap and FlatMap in terms of Javascript ( in angular perspective, rxjs 5)

In my understanding.

S

6条回答
  •  南笙
    南笙 (楼主)
    2020-12-02 06:25

    @ZahiC, cool answer - I like the use of functional composition in the code sample. If I may, like to borrow it to illustrate a couple of extra points using timed observables.

    Outer, inner, and control

    These operators are all transformation operators like map(), the common feature is they have an outer and inner observable. The key difference is the way the outer observable controls the inner observable.

    To contrast them, my code sample runs them in pairs, outputting values in the form [outerValue,innerValue]. I have added intervals to the test, and changed the inner delay so that there's some overlap in timing (formula used is delay((5-x)*200)).


    mergeMap vs concatMap

    These both output all values, the difference is the ordering.

    mergeMap - Order by inner observable
    [0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3,1],[4,1]

    concatMap - Order by outer observable
    [0,0],[0,1],[1,0],[1,1],[2,0],[2,1],[3,0],[3,1],[4,0],[4,1]

    From the output, mergeMap outer emit can be delayed in the sequence, but concatMap follows strict outer emit sequence.


    switchMap vs exhaustMap

    These both throttle the output.

    switchMap - Throttle by last
    [3,0],[4,0],[4,1]

    exhaustMap - Throttle by first
    [0,0],[0,1],[4,0],[4,1]

    From the output, switchMap throttles any incomplete inner emits, but exhaustMap throttles following emits until the earlier ones complete.


    mergeMap vs switchMap

    I threw this in because switchmap is often used in SO answers where really mergeMap should be used.

    mergeMap - Order by inner observable
    [0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3,1],[4,1]

    switchMap - Throttle by last
    [3,0],[4,0],[4,1]

    The main takeaway is that the switchMap output is unpredictable depending on the timing of the inner observable, e.g if the inner is an http get the results can depend on connection speed.


    console.clear()
    const { mergeMap, flatMap, concatMap, switchMap, exhaustMap, delay, map, take, toArray } = Rx.operators;
    
    const note = {
      mergeMap:  'Order by inner observable', 
      concatMap: 'Order by outer observable', 
      switchMap: 'Throttle by last', 
      exhaustMap: 'Throttle by first', 
    }
    const title = (operator) => {
      const opName = operator.name.replace('$1','')
      return `${opName} - ${note[opName]}`
    }
    const display = (x) => {
      return map(y => `[${x},${y}]`)
    }
    const inner = (x) => Rx.Observable.timer(0,500)
    .pipe(
      delay((5-x)*200),
      display(x),
      take(2)
    )
    
    const example = operator => () => {
      Rx.Observable.interval(500).take(5)
      .pipe(
        operator(x => inner(x)),
        toArray(),
        map(vals => vals.join(','))
      )
      .subscribe(x => {
        console.log(title(operator))
        console.log(x)
      });
    };
    
    const run = (fn1, fn2) => {
      console.clear()
      fn1()
      fn2()
    }
    const mmVcm = () => run(example(mergeMap), example(concatMap));
    const smVem = () => run(example(switchMap), example(exhaustMap));
    const mmVsm = () => run(example(mergeMap), example(switchMap));
    .examples > div {
      cursor: pointer;
      background-color: #4CAF50;
      color: white;
      padding: 7px 16px;
      display: inline-block;
    }
    
    
    
    mergeMap vs concatMap
    switchMap vs exhaustMap
    mergeMap vs switchMap

提交回复
热议问题