【问题标题】:RxJS not behaving as expectedRxJS 未按预期运行
【发布时间】:2020-08-08 04:59:27
【问题描述】:

我正在使用 RxJS 6 开发一个 Angular 8 应用程序。我认为我在使用 RxJS 方面做得很好,但今天我遇到了一些事情,让我觉得我对它的工作原理有一个根本的误解。

我有以下订阅:

this.nudgePauseConnectivity$.pipe(
    tap(() => console.log(1)),
    withLatestFrom(this.hotspotPausedState$()),
    tap(() => console.log(2)),
    filter(([nudgePause, connectionPaused]) => connectionPaused === enums.HotspotPausedStateEnum.FALSE),
    tap(() => console.log(3)),
    switchMapTo(this._store.pipe(select(this._hotspotSelectors.selectUsername))),
    tap(() => console.log(4)),
    switchMap(username =>
        this._cabinApiV2Service.subscriberService.getRemainingConnectivityAllowance(username)
    ),
    tap(() => console.log(5)),
    map(remainingConnectivityAllowance => SubscriberConnectivityAllowanceTransformer.transform(
        remainingConnectivityAllowance
    ))
).subscribe(() => {/* Do something */});

nudgePauseConnectivity$ 是我用来执行 observable 主体的主题,如下所示:

pauseConnectivity() {
    this.nudgePauseConnectivity$.next({});
}

this._hotspotSelectors.selectUsername 是一个 NgRx 选择器,如果你没有在从 store 返回值的 observable 中使用 NgRx。

我的问题是这样的:我认为表达式会对this.nudgePauseConnectivity$ 发出的每个值执行一次。我希望在控制台中看到:

1

2

3

4

5

然而,似乎即使this.nudgePauseConnectivity$ 没有发出值,如果this._store.pipe(select(this._hotspotSelectors.selectUsername)) 发出一个值,表达式的执行也会开始,所以我在控制台中看到了这种输出:

1

2

3

4

5

4

5

我对此感到非常困惑!我不希望表达式在中间开始执行:我希望表达式仅在 this.nudgePauseConnectivity$ 发出一个值时执行,而不考虑 switchMaps 或其他高阶可观察运算符中的任何表达式的值在链中。

我如何做到这一点?

【问题讨论】:

    标签: angular typescript rxjs


    【解决方案1】:

    switchMap 在第一次发射后不会取消订阅。你应该这样做。我们通常会忘记这一点,因为大多数时候我们都在处理 1 个可观察的发射,例如 http 客户端。因为您有一个在您的应用程序存在时存在的流,而不是:

    switchMapTo(this._store.pipe(select(this._hotspotSelectors.selectUsername))),
    

    您可以这样做(不中断来自 nudgePauseConnectivity$ 的所有链接 - 这会将来自 switchMap 的发射限制为单个发射,但会保留对 @987654324 的订阅@主动):

    switchMap(() => this._store.pipe(
     select(this._hotspotSelectors.selectUsername), 
     take(1)
    )
    

    如果你想在第一个发射之后中断所有发射,或者只是将take(1)放在switchMapTo之后的链中(它将在第一次发射后取消对nudgePauseConnectivity$的订阅):

    ...
    switchMapTo(this._store.pipe(select(this._hotspotSelectors.selectUsername))),
    take(1),
    ...
    

    值得查看代码的其他部分,看看您是否正确地取消订阅了所有您正在使用的可观察对象(即使是角度形式的)。

    【讨论】:

    • 这并不能解决问题,因为nudgePauseConnectivity$ observable 最终将再次发出,我希望表达式再次执行并为订阅块发出一个值。按照您的建议添加代码意味着订阅块只执行一次。
    • 如果你把take(1) 放在select 之后(第一个例子)你会得到你需要的。
    • 是的,成功了。谢谢!我真的不明白这意味着 switchMap 如何为表达式的每次运行发出一个值,以及为什么表达式的每次运行从一开始就“重置”这个 switchMap 主体,以便它可以再次发出另一个值,但我会重读几遍,看看我能不能理解它。
    猜你喜欢
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 2014-11-12
    • 1970-01-01
    • 2020-06-28
    • 2012-02-18
    • 2018-01-18
    相关资源
    最近更新 更多