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

为何我的测试用例中catchError会被调用无数次?

问题:catchError被无限执行,控制台反复打印'error!!!'

我写了如下业务代码:

makeApiCall() {
  this.client.call().pipe(
    first(),
    catchError((error, caught) => {
      console.log('error!!!');
      this.error = true;
      return caught;
    })
  ).subscribe((response: Response) => { /* 处理逻辑 */ });
}

测试代码:

let response: Subject<Response>;

beforeEach(async () => {
  response = new Subject();
  const client = jasmine.createSpyObj('Client', ['call']);
  (client.call as jasmine.Spy).and.returnValue(response);

  await TestBed.configureTestingModule({
    // 配置内容
    providers: [
      { provide: Client, useValue: client },
      // 其他依赖
    ]
  });

  describe('出现错误时', () => {
    beforeEach(() => {
      component.makeApiCall();
      response.error({ status: 422 });
    });

    it('设置错误标志', () => {
      expect(component.error).toEqual(true);
    });
  });
});

运行测试后,测试通过但控制台无数次打印'error!!!',请问为何catchError会被执行这么多次?


原因与解决方案

问题核心出在catchError里的return caught这行代码:

  • caught指向的是当前抛出错误的Observable(也就是测试里的response Subject)
  • 当Observable抛出错误时,catchError拦截错误后,如果返回caught,RxJS会重新订阅这个Observable
  • 而Subject的错误状态是持久化的——一旦调用response.error(),后续所有订阅都会立刻触发这个错误
  • 这就形成了无限循环:重新订阅→触发错误→进入catchError→返回caught→再次重新订阅……

根据你的需求,有几种解决方式:

  1. 错误处理完成后终止流,返回空Observable:
catchError((error, caught) => {
  console.log('error!!!');
  this.error = true;
  return EMPTY; // 需要导入import { EMPTY } from 'rxjs';
})
  1. 把错误继续抛出,交给上层处理:
catchError((error, caught) => {
  console.log('error!!!');
  this.error = true;
  return throwError(() => error); // 需要导入import { throwError } from 'rxjs';
})
  1. 如果需要重试请求,不要手动返回caught,改用retry操作符:
this.client.call().pipe(
  retry(2), // 最多重试2次
  first(),
  catchError((error) => {
    console.log('error!!!');
    this.error = true;
    return EMPTY;
  })
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 09:42:39