RxJS 使用指南

switchMap

switchMap 和其他打平操作符的主要区别是它具有取消效果。在每次发出时,会取消前一个内部 observable (你所提供函数的结果) 的订阅,然后订阅一个新的 observable 。你可以通过短语切换成一个新的 observable来记忆它。 它能在像 typeaheads 这样的场景下完美使用,当有新的输入时便不再关心之前请求的响应结果。在内部 observable 长期存活可能会导致内存泄露的情况下,这也是一种安全的选择,例如,如果你使用 mergeMap 和 interval,并忘记正确处理内部订阅。记住,switchMap 同一时间只维护一个内部订阅。

不过要小心,在每个请求都需要完成的情况下,考虑写数据库,你可能要避免使用 switchMap 。如果源 observable 发出速度足够快的话,switchMap 可以取消请求。在这些场景中,mergeMap 是正确的选择。

一个 v2ex 上的帖子

js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
id$ = new Subject();

price$ = id$.pipe(
    switchMap(id => getPriceById(id))
)

// merge + map 很干净,省一个 subject
isLoading$ = merge(
    id$.pipe(mapTo(true)),
    price$.pipe(mapTo(false))
);

getPriceById 需要返回一个 observable, unsubscribe 时 abort 请求即可。
切商品直接 id$.next(newId), price$ 和 isLoading$ 会自动更新。
上一次没完成的请求 switchMap 会自动 unsubscribe ,简直毫无负担。

mergeMap

  • flatMap 是 mergeMap 的别名!
  • 如果同一时间应该只有一个内部 subscription 是有效的,请尝试 switchMap
  • 如果内部 observables 发送和订阅的顺序很重要,请尝试 concatMap

exhaustMap

返回的 Observable 基于应用一个函数来发送项,该函数提供给源 Observable 发出的每个项, 并返回一个(所谓的“内部”) Observable 。当它将源值投射成 Observable 时,输出 Observable 开始发出由投射的 Observable 发出的项。然而,如果前一个投射的 Observable 还未完成的话, 那么 exhaustMap 会忽略每个新投射的 Observable 。一旦完成,它将接受并打平下一个 内部 Observable ,然后重复此过程。

js
1
2
3
4
只要没有当前活动的计时器,那么每次点击就会运行一个有限的计时器。
var clicks = Rx.Observable.fromEvent(document, 'click');
var result = clicks.exhaustMap((ev) => Rx.Observable.interval(1000).take(5));
result.subscribe(x => console.log(x));