Rxjs takeWhile完成后的链式可观察对象未被调用?

Rxjs takeWhile完成后的链式可观察对象未被调用?,rxjs,observable,Rxjs,Observable,我有以下方法,应该这样调用: registerDomain(domain) { return this._adminService.registerDomain(domain) .concatMap(operation => this.getOperationDetail(operation.OperationId)) .concatMap((op) => this.createRecordSets(op)); 应调用注册域,并应返回操作ID

我有以下方法,应该这样调用:

 registerDomain(domain) {
    return this._adminService.registerDomain(domain)
      .concatMap(operation => this.getOperationDetail(operation.OperationId))
        .concatMap((op) => this.createRecordSets(op));
  • 应调用注册域,并应返回操作ID
  • 10
    秒之后,应调用
    getOperationDetail
    传递
    operationId
  • 应每隔
    10
    秒调用一次
    getOperationDetail
    ,直到返回
    successful
  • 一旦
    getOperationDetail
    完成,就应该调用
    createRecordSets
  • 最后,应该调用
    getChangeStatus
    ,直到它返回
    INSYNC
  • 如果任何api调用引发异常,我如何在客户端处理该错误
  • 下面的代码调用registerDomain和getOperationDetail,但在getOperationDetail完成后,它不会移动到CreateRecordset

      registerDomain(domain) {
        return this._adminService.registerDomain(domain)
          .concatMap(operation => this.getOperationDetail(operation.OperationId))
          .concatMap(() => this._adminService.createRecordSets(domain));
      }
    
      getOperationDetail(operationId) {
        return Observable.interval(10000)
          .mergeMap(() => this._adminService.getOperationDetail(operationId))
          .takeWhile((info) => info.Status.Value !== 'SUCCESSFUL');
      }
      createRecordSets(caseWebsiteUrl) {
        return this._adminService.createRecordSets(caseWebsiteUrl.Url)
            .concatMap(registerId => this.getChangeStatus(registerId));
      }
    
      getChangeStatus(registerId) {
        return Observable.interval(5000)
          .mergeMap(() => this._adminService.getChange(registerId))
          .takeWhile((info) => info.ChangeInfo.Status.Value !== 'INSYNC');
      }
    
    我更新了
    getOperationDetail
    以使用
    first
    运算符:

      getOperationDetail(operationId) {
        return Observable.interval(3000)
          .mergeMap(() => this._adminService.getOperationDetail(operationId))
          .first((info) =>  info.Status.Value === 'SUCCESSFUL')
    
      }
    
    现在它实际上调用了
    createRecordSets
    ,但是在
    createRecordSets
    之后,它继续调用
    getOperationDetail
    大约13次,并最终调用
    getChangeStatus
    。从我的角度来看,我认为它会:

  • 调用
    getOperationDetail
    ,直到它收到
    SUCCESS
  • 调用
    createRecordset
    一次
  • 调用
    getChangeStatus
    ,直到它收到
    INSYNC
  • 完成了
  • 为什么会有额外的电话

    我将注册域更改为如下所示:

     registerDomain(domain) {
        return this._adminService.registerDomain(domain)
          .concatMap(operation => this.getOperationDetail(operation.OperationId))
            .concatMap((op) => this.createRecordSets(op));
    

    在我将
    .concatMap((op)=>this.createRecordSets(op))
    链接到
    this.getOperationDetail
    之后之前。一旦我把它移到外面,它就开始正常工作了。但我不确定为什么。有人能解释一下吗?

    takeWhile
    满足一个满足特定标准的值时,它完成了可观察的,而不传播该值。这意味着下一个链式运算符将不会接收该值,也不会调用其回调

    假设在您的示例中,对this.\u adminService.getOperationDetail(…)的前两个调用导致非成功状态,第三个调用成功。这意味着
    getOperationDetail()
    返回的可观察值将只产生两个
    info
    值,每个值都具有非成功状态。同样重要的是,下一个链式
    concatMap
    操作符将根据每个不成功的值调用其回调,这意味着
    createRecordset()
    将被调用两次。我想你可能想避免这样

    我建议使用
    第一个
    操作符:

    getOperationDetail(operationId) {
        return Observable.interval(10000)
            .concatMap(() => this._adminService.getOperationDetail(operationId))
            .first(info => info.Status.Value !== 'SUCCESSFUL');
    }
    
    这样
    getOperationDetail()
    将在
    This.\u adminService.getOperationDetail(operationId)
    成功时只生成一个“成功”值。操作符发出与指定条件匹配的源可观测值的第一个值,然后完成

    当涉及到错误处理时,或运算符可能很有用

    更新:

    您所面临的意外行为(
    getOperationDetail()
    first()
    完成后继续被调用)似乎是在
    rxjs
    中出现的。如中所述

    每个take-ish操作符(完成时间早于其源可观测值的操作符)在与延长订阅时间的操作符(此处为switchMap)组合时,将继续订阅源可观测值

    first
    takeWhile
    都是此类take-ish操作符的示例,而“延长”订阅的操作符是,例如,
    switchMap
    concatMap
    mergeMap
    。在以下示例中,当
    concatMap
    的内部可观测值发出值时,将记录数字:

    var takeish$ = Rx.Observable.interval(200)
        // will keep logging until inner observable of `concatMap` is completed
        .do(x => console.log(x))
        .takeWhile(x => x < 2);
    
    var source = takeish$
        .concatMap(x => Rx.Observable.interval(200).take(10))
        .subscribe();
    

    您好,我先尝试了一下,效果不错,但我遇到了一个问题。我用它更新了我的帖子。我想我成功地重现了你描述的意外行为,我会很快更新答案。简而言之,
    first()
    即使在满足指定的条件后,似乎也不会从可观察的源中取消订阅,有关详细信息,请参阅。@xaisoft,我用错误描述和可能的解决方法更新了答案。坦白地说,这个错误让我大吃一惊:)嗨,谢尔盖,我很感谢你的回答。我还发布了一个带有简单示例的问题,得到了以下回复。看起来已经修好了@xaisoft,你发布的另一个问题是绝对正确的,但它与你描述的bug无关。我相当肯定,该缺陷仍然存在于rxjs的当前版本(目前为5.4.2)中,它与
    first
    操作符是否与
    concatMap
    操作符链接有关。我更新了我的答案,提供了更多细节和几个可运行的代码片段来说明这个问题。