RxJS:switchMap / mergeMap中的扫描运算符

时间:2019-03-20 17:59:33

标签: typescript rxjs

我们将扫描运算符用于表格中的“加载更多”按钮。使用扫描运算符,我们仅将新结果与先前的结果进行累加。 但是,我们遇到了一些意外的行为。

为简单起见,假设我们有以下代码:

const fakeRequest = of('response').pipe(delay(2000));
interval(1000).pipe(
    mergeMap(_ => fakeRequest),
    scan<string>((allResponses, currentResponse) => [...allResponses, currentResponse], []),
).subscribe(console.log);

产生:

["response"]
["response", "response"]
["response", "response", "response"]
["response", "response", "response", "response"]
...

同时,如果我们只是将扫描运算符移到mergeMap / switchMap运算符内:

interval(1000).pipe(
    mergeMap(_ => fakeRequest.pipe(
        scan<string>((allResponses, currentResponse) => [...allResponses, currentResponse], []),
    )),
).subscribe(console.log);

我们得到以下结果:

["response"]
["response"]
["response"]
["response"]
...

在第二个示例中不执行扫描运算符。我希望switchMap / mergeMap能够使内部可观察的对象变平,其中将扫描运算符引入其中。

  • 这是期望的行为吗?
  • 如果是这样,有人可以解释为什么会这样吗?
  • 如果是这样,是否有另一种方法/解决方法可以在mergeMap或switchMap运算符内实现相同的行为?

谢谢!

1 个答案:

答案 0 :(得分:1)

不同的原因是因为在第一种情况下:

interval(1000).pipe(
    mergeMap(_ => fakeRequest),
    scan<string>((allResponses, currentResponse) => [...allResponses, currentResponse], []),
)

您正在 scan 控制 mergeMap 内创建的所有可观察量的排放。

然而,在第二种情况下:

interval(1000).pipe(
    mergeMap(_ => fakeRequest.pipe(
        scan<string>((allResponses, currentResponse) => [...allResponses, currentResponse], []),
    )),
)

您正在scan控制一个 observable 的发射,它只发射一次!

本质上,mergeMap() 是一个多次发射的源。 fakeResponse observable 是一个只发出一次的源。

我从您的评论中看到,您希望在响应下移动 scan 的原因是希望在您的服务中执行 scan,因此个人消费者不需要这样做。我知道这是一个老问题,所以也许您现在已经想通了,但是您当然可以通过添加 .pipe(scan(...)) .