You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用RxJS替代递归setTimeout实现上传状态查询请求的重试?

用RxJS实现轮询获取文件上传状态

当然可以用RxJS的操作符实现这种轮询逻辑,相比递归setTimeout,RxJS的方案更符合响应式编程思想,代码更简洁可控,也更容易管理订阅生命周期。

下面是重构后的实现代码:

checkImportStatus(): void {
  this.restaurantService.getImportStatus().pipe(
    // 递归处理轮询:若响应非终态,延迟3秒后再次发起请求
    expand(res => {
      if (res.result.status !== 'success' && res.result.status !== 'error') {
        return timer(3000).pipe(switchMap(() => this.restaurantService.getImportStatus()));
      }
      // 终态时结束流
      return EMPTY;
    }),
    // 组件销毁时终止订阅,避免内存泄漏
    takeUntil(this.destroy$),
    // 仅获取最后一个终态响应
    last()
  ).subscribe({
    next: (res) => {
      this.spinner.hide();
      if (res.result.status === 'error') {
        this.toastr.error(res.result.restaurant.message, 'Error!');
      } else {
        this.toastr.success(res.result.message, 'Success');
      }
    },
    error: (err) => {
      console.error(err);
      this.spinner.hide();
      this.toastr.error('获取上传状态失败', '错误');
    }
  });
}

关键操作符说明

  • expand:对源Observable发出的每个值返回新的Observable,实现递归轮询逻辑。当响应不是success或error时,返回延迟3秒后的新请求;终态时返回EMPTY结束流。
  • timer(3000):替代setTimeout实现3秒延迟,符合RxJS的响应式风格。
  • switchMap:将延迟事件映射为新的状态请求。
  • last():过滤掉中间的非终态响应,只保留最后一个终态结果用于处理。
  • takeUntil(this.destroy$):和原逻辑保持一致,确保组件销毁时取消订阅,避免内存泄漏。

扩展优化(可选)

如果需要添加最大重试次数或超时限制(比如你提到的4分钟耗时上限),可以直接在管道中添加对应操作符:

checkImportStatus(): void {
  this.restaurantService.getImportStatus().pipe(
    expand((res, index) => {
      // 限制最多重试20次(对应21次请求)
      if (index >= 20) return EMPTY;
      if (res.result.status !== 'success' && res.result.status !== 'error') {
        return timer(3000).pipe(switchMap(() => this.restaurantService.getImportStatus()));
      }
      return EMPTY;
    }),
    // 设置4分钟超时
    timeout(4 * 60 * 1000),
    takeUntil(this.destroy$),
    last()
  ).subscribe({
    next: (res) => {
      this.spinner.hide();
      if (res.result.status === 'error') {
        this.toastr.error(res.result.restaurant.message, 'Error!');
      } else {
        this.toastr.success(res.result.message, 'Success');
      }
    },
    error: (err) => {
      console.error(err);
      this.spinner.hide();
      if (err.name === 'TimeoutError') {
        this.toastr.error('请求超时,请稍后重试', '超时');
      } else {
        this.toastr.error('获取上传状态失败', '错误');
      }
    }
  });
}

内容的提问来源于stack exchange,提问作者RAHUL KUNDU

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 20:40:34