【问题标题】:RxJS: scan operator inside switchMap/mergeMapRxJS:switchMap/mergeMap 中的扫描运算符
【发布时间】:2021-02-11 04:11:36
【问题描述】:

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

为了简化,假设我们有以下代码:

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 只是将内部 observable 展平,其中将扫描运算符通过管道输送到其中。

  • 这是期望的行为吗?
  • 如果是这样,谁能解释为什么会这样?
  • 如果是这样,是否有其他方法/解决方法可以在 mergeMap 或 switchMap 运算符中实现相同的行为?

谢谢!

【问题讨论】:

  • 我认为这与 scan() 处理发出的数据的事实有关,mergeMap 在将值映射到外部 observable 之前完成订阅内部 observable 的工作。如果您将 scan() 运算符放在 fakeRequest 声明语句中,可能会更清楚的是,扫描没有得到任何值,因为 of().pipe(delay()) 从未订阅发出 'response '。
  • 您的第一个示例运行良好,为什么要切换到第二个示例
  • @FanCheung 1. 因为我们的 fakeRequest observable 来自服务。我们希望在我们的数据服务中包含扫描功能,因为它属于那里。但是,出于某种原因,我们不得不在页面组件中使用 switchMap。现在我们需要在我们的组件中添加扫描功能,这不是我们想要的,而且是非常意外的行为。我们认为 switchMap 几乎会“切换”到内部的 Observable,包括扫描操作符。 2. 只是想了解这些怪癖。我们没想到内部 observable 的操作符会被“忽略”。

标签: typescript rxjs


【解决方案1】:

产生差异的原因是因为在第一种情况下:

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

您是scanning 来自mergeMap 中创建的所有可观察对象的排放。

但是,在第二种情况下:

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

你是 scanning 来自一个 observable 的发射,它只发射一次!

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

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

【讨论】:

    猜你喜欢
    • 2014-03-29
    • 2021-11-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-11
    • 1970-01-01
    • 2017-06-26
    • 2021-12-16
    • 1970-01-01
    相关资源
    最近更新 更多