我无法找到这个问题的答案,但concat map和map之间有什么区别?具体来说,我有一个让我感到困惑的例子:
const domainsObservable = this.auth.getAuthDomains()
.shareReplay()
.concatMap((authDomains) => authDomains.map((domain) => this.toDomain(domain, connectionsObservable)))
.filter((authDomain) => this.isValidDomain(authDomain))
.toArray();
这是从服务getAuthDomains()
调用一个方法,它返回了一个包含3个域的数组。当我使用上面的实现时,我最终得到了一个由4个数组组成的数组,每个数组都有一个包含3个域的数组。不知何故,它使响应中的数据量翻了两番。
然后我切换到以下实现:
const domainsObservable = this.auth.getAuthDomains()
.shareReplay()
.map(authDomains => authDomains.map(domain => this.toDomain(domain, connectionsObservable)))
.map(authDomains => authDomains.filter(domain => this.isValidDomain(domain)));
这正是我所需要的 - 一个被正确过滤的数组。
那么为什么切换到map
会大大改变结果呢?我的操作顺序是否重要?
由于
答案 0 :(得分:6)
简单地说两位运营商做了以下事情:
map()
- 将每个值投射到一个不同的值中,该值在链中进一步传播:
.map(v => v * 2)
这与Array.map()
基本相同。
concatMap()
- 将每个值投影到Observable中并订阅它。运算符总是只订阅一个内部Observable,因此如果源Observable更快地发出值,它们将被缓存在concatMap()
内:
.concatMap(v => Observable.of(v * 2))
...或者通常在Angular中你会做这样的事情:
.concatMap(v => this.http.get(`whatever/${v}`))
但是有趣的部分来了。在RxJS 5中,订阅内部Observables(从投影函数返回的Observable等)的运算符实际上期望所谓的“可观察输入”。这意味着您可以自由地交换Observables,Promises,Observables类对象,以及JavaScript数组。
在内部使用subscribeToResult
功能实现。请注意,如果您将数组传递给它,它将迭代它并单独发出每个值:https://github.com/ReactiveX/rxjs/blob/master/src/internal/util/subscribeToResult.ts#L17
这意味着您可以使用concatMap()
将数组“解包”成单个发射。例如:
Observable.of(42)
.concatMap(v => [1, 2, 3])
.subscribe(console.log)
这将打印数字:
1
2
3
另一方面,如果你只使用map
,它只会进一步传递数组:
Observable.of(42)
.map(v => [1, 2, 3])
.subscribe(console.log)
这将打印数字:
[1,2,3]
所以concatMap
有时仅用于解析来自源Observable的数组concatMap(array => array)
,这正是代码中正在发生的事情。
哪一个更好取决于你。通常,在Array对象本身上执行简单操作(如map
或filter
)更容易,而不是出于性能原因在Rx链中进行解包和处理。