【问题标题】:switchMap operation only running on first call?switchMap 操作仅在第一次调用时运行?
【发布时间】:2018-01-06 04:05:07
【问题描述】:

我有一个 Angular 应用程序,它向 Http 服务发出请求并在另一个 Http 服务上调用 switchMap。由于某种原因,switchMap 中的请求仅在第一次调用父调用时运行。否则父请求会触发而 switchMap 不会触发,代码如下:

this._receivableService.newTenantDebitCredit(tenantCredit)
            .take(1)
            .switchMap(result =>
                // Refresh the lease receivables before giving result
                this._receivableService.getAll({
                    refresh: true,
                    where: { leaseId: this.leaseId }
                }).take(1).map(() => result)
            )
            .subscribe(
                ...
            )

如何在每次调用上面的 newTenantDebitCredit 方法时运行 switch 映射中的 getAll 请求?

编辑:这是在click 上调用的函数的全部内容。当我第一次单击给定单元的按钮时,两种方法都会执行。如果我尝试一个已经调用了该方法的单元(没有刷新),则只执行第一个方法。我意识到很多事情可能还不清楚,目前这是一个相当大的项目。

public submitTenantCredit() {
        this.isLoading = true;
        let tenantCredit: NewTenantDebitCreditData;
        let receivableDefinitions: ReceivableDefinition[] = [];

        // construct receivable defintions for NewTenantDebitData model
        receivableDefinitions = this._constructReceivableDefinitions();

        // construct data we will be POSTing to server.
        tenantCredit = new NewTenantDebitCreditData({
            siteId: this._apiConfig.siteId,
            leaseId: this.leaseId,
            isCredit: true,
            receivables: receivableDefinitions,
            reason: this.actionReason
        });

        // make service call and handle response
        this._receivableService.newTenantDebitCredit(tenantCredit)
            .take(1)
            .switchMap(result =>
                // Refresh the lease receivables before giving result
                this._receivableService.getAll({
                    refresh: true,
                    where: { leaseId: this.leaseId }
                }).take(1).map(() => result)
        )
            .take(1)
            .subscribe(
                (receivables) => {
                    this.closeReasonModal();
                    let refreshLeaseId = this.leaseId;
                    this.leaseId = refreshLeaseId;
                    this.isLoading = false;
                    this.refreshBool = !this.refreshBool;
                    this._debitCreditService.refreshUnitInfo();
                    this._notifications.success(`The tenant credit for ${this.customerName} - Unit ${this.unitNumber} was submitted successfully`);
                },
                (error) => {
                    console.error(error);
                    this.isLoading = false;
                }
            )
    }

如果有帮助,newTenantDebitCredit() 是 HTTP POST 请求,getAll()GET 请求。

【问题讨论】:

  • 可以尝试将getAll 包裹在Observable.defer 中吗?文档reactivex.io/documentation/operators/defer.html
  • defer 只是冻结了请求。
  • 你能提供这个的代码吗?_receivableService.newTenantDebitCredit
  • @Zachscs 正如@FanCheung 指出的,还请提供ReceivableService 的样子;至少这里使用的两种方法。
  • 应收款服务扩展了有自己定义的基础 API 服务。这对 SO 来说可能不是一个好问题。

标签: javascript angular rxjs


【解决方案1】:

您使用了 take 运算符。当您的服务 observable 将发出时,take 运算符将首先执行,并且 take 将仅链接 observable 中的第一个发出。您的代码不会使用后续的发射。 如果您想从 observable 中获取所有发射,请从您的代码中删除 take。

希望它会有所帮助。

【讨论】:

  • 我删除了两个 take 语句,但并没有解决问题。
  • 你试过用mergeMap代替switchMap吗?对于mergeMap,不会取消订阅。
  • @SamuelShyu 你的意思是要删除take吗?需要移除哪些 Take 运算符?删除所有并使用 mergemap 并不能解决问题。
  • 当我明确表示它对这个问题没有影响时,怎么会有人支持它......
  • 是发出 1 并完成的冷请求,因此 take(1) 无效。删除它不会解决问题。投反对票
【解决方案2】:

单独测试 Rx 代码,这是一个模型。控制台日志每次都会发生,所以我认为您使用的 Rx 没问题。

对可能罪魁祸首的最佳猜测是this.refreshBool = !this.refreshBool,但我们需要查看newTenantDebitCreditgetAll 的内部结构才能确定。

// Some mocking
const _receivableService = {
  newTenantDebitCredit: (tc) => {
    console.log('inside newTenantDebitCredit')
    return Rx.Observable.of({prop1:'someValue'})
  },
  getAll: (options) => {
    console.log('inside getAll')
    return Rx.Observable.of({prop2:'anotherValue'})
  }
}
const tenantCredit = {}

// Test
_receivableService.newTenantDebitCredit(tenantCredit)
  .take(1)
  .switchMap(result => {
    console.log('result', result)
    return _receivableService.getAll({ 
      refresh: true,
      where: { leaseId: this.leaseId }
    })
    .take(1)
    .map(() => result)
  })
  .take(1)
  .subscribe(
    (receivables) => {
      console.log('receivables', receivables)
      //this.refreshBool = !this.refreshBool;
    },
    (error) => {
      console.error(error);
    }
  )
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>

【讨论】:

  • 我认为第三个 take 1 是不必要的,在 switchMap 你订阅返回的 Observable 已经使用了 take 操作符。它只能发出一个值而不是完成。
  • 我只是逐字复制了@Zachscs 代码,因为我只是想看看 Rx 是否正常工作 - 确实如此。
  • 当然,我会写一些不同的东西,但这篇文章的重点是表明每次单击按钮时switchMap() 都会触发两个观察者。
  • 所以,现在我需要查看更多代码才能进一步取得进展。我希望@Zachscs 会答应,否则他可能会浪费他的赏金积分。
  • 好吧,我明白了,对不起。是的,我认为该服务会提供更多见解。在大多数“getAll”/“getMultiple”操作的情况下,我喜欢使用 forkjoin。
【解决方案3】:

首先,这与switchMap 运算符无关。

通常删除take(1) 会导致这种行为。在这种情况下,它不会因为它不是所谓的热可观察对象。

问题是您使用的是http.post。这是一个冷可观察对象,这意味着它只会返回一个值。这也是您不需要退订的原因。它永远不会开火两次。可能的解决方案可能是:

  1. 使用网络套接字获取实时数据。
  2. 创建一个将定期获取数据的计时器。
  3. 只需在需要时再次获取数据。

【讨论】:

  • 所以第一个请求是一个post请求,它是由点击事件触发的。每次都会触发这个。 switchMapped 到 post 的 get 请求是只触发一次的请求。
  • 可以添加请求的方法吗?
【解决方案4】:

你提问的方式

如何在每次调用上面的 newTenantDebitCredit 方法时运行 switch 映射中的 getAll 请求?

实际上,在我看来,您从代码中的某处调用newTenantDebitCredit,期待第二个请求发生;所以我认为这可能是对可观察链如何工作的误解。我们举个例子:

const source$ = Observable.of(42);
source$
  .map(value => 2 * value)
  .subscribe(console.log);
source$
  .subscribe(console.log);

您希望这会记录什么?如果您的答案是“它会记录 84 两次”,那就错了:它记录了 84 和 42。

从概念上讲,您的情况是一样的。第二个请求仅在newTenantDebitCredit() 发出的observable返回时发生;任何来电者致电newTenantDebitCredit 时都不会发生这种情况。这是因为 observable 链不会就地改变 observable,它们只会返回一个 new observable。


如果您希望发生第二个请求,您必须实际更改newTenantDebitCredit 方法的定义以返回一个可观察的设置来执行第二个请求;或者,设置一个您订阅的链式可观察对象,而不是调用newTenantDebitCredit

【讨论】:

  • 但是第二个请求是第一次发生?
  • 另外我正在调用一个方法,上面的代码是内容。所以 switchMap 始终是newTenantDebitCredit() 的一部分
  • @Zachscs 我可以解释为什么第二个请求被调用一次,但如果你每次都调用整个链,我的解释是无效的。不过,我认为是时候展示更完整的代码场景了:所涉及的方法是什么样的,以及调用的内容和方式。
  • 我把整个函数贴出来了,可能还不清楚是怎么回事。
【解决方案5】:

不是一个真正的答案,但我确实解决了我的问题。它几乎肯定对任何人都没有用,但这是应收账款服务中的一个问题,它没有正确地对boolean:refresh 进行攻击,并且在第一次之后从缓存中提取值。

【讨论】:

    猜你喜欢
    • 2012-04-23
    • 1970-01-01
    • 2020-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-17
    • 2021-03-04
    • 1970-01-01
    相关资源
    最近更新 更多