switchMap操作只在第一次调用时运行?

时间:2017-12-22 19:18:20

标签: javascript angular rxjs

我有一个角度应用程序,它向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 map中运行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请求。

5 个答案:

答案 0 :(得分:3)

您使用了take运算符。当你的服务可观察性将发出时,take运算符将首先执行并且take将仅链接从observable发出。您的代码不会进行后续发射。 如果你想从observable中获取所有的emits,那么从你的代码中删除take。

希望它会有所帮助。

答案 1 :(得分:3)

单独测试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>
&#13;
&#13;
&#13;

答案 2 :(得分:2)

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

正常删除take(1)会导致此行为。在这种情况下它不会,因为它不是一个所谓的热观察。

问题是您使用的是http.post。这是一个冷可观察,这意味着它只返回一次值。这也是您不需要取消订阅的原因。它永远不会发射两次。可能的解决办法可能是:

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

答案 3 :(得分:1)

您提出问题的方式

  

每次在上面调用newTenantDebitCredit方法时,如何在switch map中运行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时不会发生这种情况。这是因为可观察链不会使就地观察变异,它们只会返回 new observable。

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

答案 4 :(得分:0)

不是答案,但我确实解决了我的问题。它几乎肯定对任何人都没用。但是它是可接收服务中的一个问题,它没有正确地监视booleanrefresh并且是第一次从缓存中提取值。