【问题标题】:Observable retry / retryWhen with flatmap可观察的重试 / retryWhen 与 flatmap
【发布时间】:2018-01-04 10:15:50
【问题描述】:

我有以下代码来获取id,然后获取与id相关的数据。

process(): Observable<any> {
    let id: number;
    return this.getId().flatMap(
        (response: number) => {
                id = response;
                return this.getData(id)
        }
    ).flatMap(
        (data: any) => {
            return Observable.of(data);
        }
    );
}

getData(id: number): Observable<any> {
    // retry if response.status is not complete
    return this.service.getData(id).map(response => return response.data); 
}

我想在 getData 方法上添加重试逻辑,直到 response.status 未完成。我尝试在 this.getData(id) 之后添加 retry/retryWhen 但没有运气。请问有什么建议吗?

【问题讨论】:

    标签: javascript angular rxjs observable


    【解决方案1】:

    retryretryWhen 适用于错误处理,这意味着源 observable 必须产生错误才能使这些运算符生效。我想在你的情况下你想重试不是错误,而是你不喜欢的状态。

    实现这一目标的最简单方法可能是每隔一段时间进行一次服务调用,并以您想要的状态获取第一个响应:

    getData(id) {
        return Observable.interval(100)
            // make 5 attempts to get the data
            .take(5)
            .concatMap(() => this.service.getData(id))
            .filter(response => response.status === "complete")
            .take(1)
            .map(response => response.data)
    }
    

    现在getData() 返回一个 observable,它要么发出一个对应于具有“完成”状态的响应的单个值,然后完成,或者在 5 次尝试获取数据失败后完成而不发出任何值期望的状态(响应评论更新的答案)

    更新:

    当然,可以将“坏”状态的响应转换为错误并使用retry 功能,正如您所建议的:

    getData(id) {
        return this.service.getData(id)
            .concatMap(response => response.status === "complete" ?
                Observable.of(response) :
                Observable.throw("Bad status"))
            .map(response => response.data)
            .retry(5);
    }
    

    如果出现问题,此代码将尝试获取数据最多 6 次(1 次初始 + 5 次重试),然后将产生一个您必须处理的错误,例如使用 catch 运算符。一个缺点是这种方式无法区分“真实”错误(例如网络故障)和由不良状态产生的错误,但这可以通过retryWhen 处理。

    【讨论】:

    • 你是对的,retry和retryWhen都适合错误处理。我想在尝试 x 次后停止重试,是否可以在您的代码中包含此条件?
    • 或者,是否可以根据状态创建错误结果来使用retry和retryWhen?
    • 两种方式都可以,我更新了初始解决方案 (.take(5)) 并添加了另一个解决方案 (retry(5))。请注意,当指定的重试次数不够时,您需要处理一个案例,例如.catch(() =&gt; Observable.empty()) 或其他适合您需求的方式。
    • 我还在原始解决方案中将 'first(...)` 替换为 'filter(...).take(1)' 以避免 'first()' 产生的错误如果源 observable 完成而没有发出任何满足条件的值。
    【解决方案2】:

    我已经尝试过重试方法并且它有效。

    (Observable ...).retry(2).map(...).subscribe(...)
    

    当我进行 http 调用并且响应是例如 404 时,它会重试调用两次。

    【讨论】:

      猜你喜欢
      • 2017-01-01
      • 2019-07-13
      • 1970-01-01
      • 1970-01-01
      • 2017-12-28
      • 2014-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多