【问题标题】:Catching errors in rxjs with mergeMap operator使用 mergeMap 运算符捕获 rxjs 中的错误
【发布时间】:2025-11-27 02:25:02
【问题描述】:

我写了一个代码,我想在发生异常时捕获一个错误:

this.assetApiService.getAssets(new AssetSearchCriteriaDto({tags: [AssetTags.tenant]})).pipe(
          catchError(error => {
           console.log(error);
          }),
          (mergeMap((assets: AssetDto[]) => {
                this.appInitStorageService.setAvailableTenants(assets);
                return this.userApiService.getUserById(this.authApiService.getAuth().userInfo.id);
              }
            )
          )
        )
          .subscribe((user: UserDto) => {
            this.persistSelectedUserLanguage(user);
            this.appInitStorageService.setUser(user);
            resolve();
          }, error => {
            console.log('error:', error);
          });

我们的目标是捕捉错误,如果它们发生在序列中的第一个可观察对象(getAssets)或第二个可观察对象(getUserById)中。我在第一个中添加了 catchError 运算符,但我看不到 console.log(error)。我不知道为什么。在这个例子中我应该如何正确地捕捉错误?

【问题讨论】:

    标签: angular rxjs observable mergemap


    【解决方案1】:

    您只需将catchError 移到mergeMap 下方即可捕获两个可观察对象的错误。同样重要的是要记住 catchError 必须返回一个 observable。你可以使用 RxJS throwError 函数抛出一个可观察到的错误

    this.assetApiService.getAssets(new AssetSearchCriteriaDto({tags: [AssetTags.tenant]})).pipe(
      mergeMap((assets: AssetDto[]) => {
        this.appInitStorageService.setAvailableTenants(assets);
        return this.userApiService.getUserById(this.authApiService.getAuth().userInfo.id);
      }),
      catchError(error => {
        console.log(error);
        return throwError(error); // return error that will trigger the subscriptions `error` block
      })
    ).subscribe({
      next: (user: UserDto) => {
        this.persistSelectedUserLanguage(user);
        this.appInitStorageService.setUser(user);
        resolve();
      }, 
      error: error => {
        console.log('error:', error);
      }
    });
    

    另一方面,如果您希望将错误转换为有效排放并因此保持流运行而不是出错,您可以使用 RxJS of 函数。错误将被发送到订阅的next 回调而不是error 回调

    this.assetApiService.getAssets(new AssetSearchCriteriaDto({tags: [AssetTags.tenant]})).pipe(
      mergeMap((assets: AssetDto[]) => {
        this.appInitStorageService.setAvailableTenants(assets);
        return this.userApiService.getUserById(this.authApiService.getAuth().userInfo.id);
      }),
      catchError(error => {
        console.log(error);
        return of(error); // return error that will trigger the subscriptions `next` block
      })
    ).subscribe({...});
    

    【讨论】:

    • 我更改了操作符的顺序,但我仍然看不到控制台日志。你不知道为什么?
    • 你是指catchError里面的console.log还是订阅?
    • 是的。我看不到。
    • 这不是一个是/否的问题吗?你是指哪个console.log
    • 我的意思是这部分:catchError(error => { console.log("error", error); return of(error); // 返回错误会触发订阅 next block } )
    【解决方案2】:

    您的代码是否正在编译?你必须在catchError 中返回一个 Observable:

    catchError(error => {
        console.log(error);
        return of([ ]);
    }),
    

    这样,在捕获到错误后,流可以继续处理。如您所见,catchError 仅在您可以恢复控制流时才有意义 - 否则错误可能会冒泡到订阅错误处理程序。一个很大的区别在于,如果错误到达订阅,observable 将停止发射,而 catchError 它将继续发射(这与您的情况无关,但例如在 intervalfromEvent Observable 的情况下发出多个值)。

    如果这不能解决您的问题,请确保 this.assetApiService.getAssets 实际上会引发异常。也许它只是出于某种原因返回带有错误响应代码的响应?

    【讨论】:

    • "catchError 仅在您可以恢复控制流时才有意义" - 这是值得商榷的。在具有多个可观察对象的流中,我可以单独处理来自每个可观察对象的错误。但这并不意味着必须恢复流量。我可以使用throwError 返回错误,订阅中更通用的错误处理可能会捕获该错误。简而言之,这取决于用例。在某些情况下,需要在处理错误后停止流,而在某些情况下,不一定需要。
    • 另一个常见用例是错误处理 + retry/retryWhencatchError 用于处理错误并使用throwError 再次发出错误,确保使用retryretryWhen 运算符重新启动流。
    最近更新 更多