美文网首页web前端高级-vue
彻底理解RxJS拉平策略:mergeMap/switchMap/

彻底理解RxJS拉平策略:mergeMap/switchMap/

作者: 老鼠AI大米_Java全栈 | 来源:发表于2022-05-19 16:01 被阅读0次

map 操作想必大家一定不陌生:

const { of } = Rx;
const { map  } = RxOperators;

const namesObservable = of('A', 'B');
namesObservable.pipe(
   map(name => `map ${name}`)
)

namesObservable .subscribe(result => console.log(`${result}`))

// map A
// map B

很直观,因为 map 映射的是“值”,所以足够简单~

但是,如果说,map 映射的是 observable 呢 ?

const { of } = Rx;
const { map } = RxOperators;

const namesObservable = of('A', 'B');

const http =(name)=>{
      return of(`${name} 1`,`${name} 2`);
}

namesObservable.pipe(
   map(name => http(name))
)

namesObservable.subscribe(result => console.log(`${result}`))

// 则会得到两个 observable 对象
// ****observable{ .. }
// observable{ .. }

结果发现,最终得到的仍是 observable;在 https://rxviz.com/ 的弹珠图中,可以看到:

image.png

observable 由最初的 1 个,变成了 2 个(圆圈就是 observable),数据仍在里面没有被订阅解析出来。

虽然,我们可以用粗暴的方法,在订阅 .subscribe 里面再次调用订阅 .subscribe ,则可以得值:

const { of } = Rx;
const { map } = RxOperators;

const namesObservable = of('A', 'B');

const http =(name)=>{
      return of(`${name} 1`,`${name} 2`);
}

namesObservable.pipe(
   map(name => http(name))
)

namesObservable .subscribe(resultObservable => { 
   resultObservable.subscribe(result => console.log(`${result}`) )
})

// A1
// A2
// B1
// B2

但是,这样包裹写法注定是不优雅的,所以,为了解决这个差异,RxJS 引入了 —— Flattening(扁平化)策略!!

我们可以借助 flatMap 操作符,则能得到同样的解析值的效果~ flatMap 其实也就是我们熟知的 mergeMap 操作符;

代码如下:

const { of } = Rx;
const { mergeMap} = RxOperators;

const namesObservable = of('A', 'B');

const http =(name)=>{
      return of(`${name} 1`,`${name} 2`);
}

namesObservable.pipe(
   mergeMap(name => http(name))
)

namesObservable.subscribe(result => console.log(`${result}`))
// A1
// A2
// B1
// B2

更进一步,沿着这种偏平化策略思路,除了 mergeMap,RxJS 又引入了 switchMap、concatMap 和 exhaustMap,它们能够提供不同种类的拉平策略。

我们借助 https://rxviz.com/ 的弹珠图,一眼便能看到它们的差异:

我们设置一个定时器,每一秒都发出一个 observable,一共发 3 次,来看下分别得值;

  • mergeMap
    当想要打平内部 observable 并手动控制内部订阅数量时,此操作符是最适合的。
const { of,interval} = Rx;
const { mergeMap,take,map } = RxOperators;

const namesObservable = of('A', 'B');

const http =(name)=>{
      return interval(1000)
      .pipe(
        take(3),
        map(()=>of(`${name} 1`,`${name} 2`))
      )
}

namesObservable.pipe(
   mergeMap(name => http(name))
)
image.png
  • switchMap
    switchMap 和其他打平操作符的主要区别是它具有取消效果。在每次发出时,会取消前一个内部 observable (你所提供函数的结果) 的订阅,然后订阅一个新的 observable 。你可以通过短语切换成一个新的 observable来记忆它。
const { of,interval} = Rx;
const { switchMap,take,map } = RxOperators;

const namesObservable = of('A', 'B');

const http =(name)=>{
      return interval(1000)
      .pipe(
        take(3),
        map(()=>of(`${name} 1`,`${name} 2`))
      )
}

namesObservable.pipe(
   switchMap(name => http(name))
)
image.png
  • concatMap
    将值映射成内部 observable,并按顺序订阅和发出。
const { of,interval} = Rx;
const { concatMap ,take,map } = RxOperators;

const namesObservable = of('A', 'B');

const http =(name)=>{
      return interval(1000)
      .pipe(
        take(3),
        map(()=>of(`${name} 1`,`${name} 2`))
      )
}

namesObservable.pipe(
   concatMap (name => http(name))
)
image.png
  • exhaustMap
    映射成内部 observable,忽略其他值直到该 observable 完成。
const { of,interval} = Rx;
const { exhaustMap ,take,map } = RxOperators;

const namesObservable = of('A', 'B');

const http =(name)=>{
      return interval(1000)
      .pipe(
        take(3),
        map(()=>of(`${name} 1`,`${name} 2`))
      )
}

namesObservable.pipe(
   exhaustMap (name => http(name))
)
image.png

相关文章

网友评论

    本文标题:彻底理解RxJS拉平策略:mergeMap/switchMap/

    本文链接:https://www.haomeiwen.com/subject/dxptprtx.html