FORKJOIN 发生错误后不会停止后续请求

问题描述 投票:0回答:1

问题在于,即使前一个查询失败,forkjoin 数组中的查询也会继续执行。例如,在第一个请求 putCategory$ 中已经发生错误(名称已存在)。但是,执行下一个 loadImage$ 请求并且仍然加载新图像。为什么?如何发出一系列请求,以便在发生故障时不会执行下一个请求?

 PUTCategory(category: ICategory) {
    const newImage = category.image;
    const oldImage = this.editedCategory.image;
    const imageChanged = oldImage !== newImage;
    const loadImage = imageChanged && !!newImage;
    const deleteImage = imageChanged && !!oldImage;

    const file: File = this.form.value.image;

    const putCategory$ = this.categoryService.putCategory(category).pipe(
      catchError((response: any) => {
        if (response.error.info == 'NAME_EXISTS') {
          this.throwErrorModal(
            'Категория с таким названием уже существует. Измените название и попробуйте снова.',
          );
        } else {
          this.throwErrorModal(
            'Произошла ошибка при попытке обновить категорию',
          );
        }
        return EMPTY;
      }),
    );

    const loadImage$ = loadImage
      ? this.categoryService.uploadCategoryImage(file).pipe(
          catchError(() => {
            this.throwErrorModal(
              'Произошла ошибка при попытке загрузить файл нового изображения категории',
            );
            return EMPTY;
          }),
          concatMap((response: any) => {
            const filename = response.filename;
            return this.categoryService
              .setImageToCategory(category.id, filename)
              .pipe(
                catchError(() => {
                  this.throwErrorModal(
                    'Произошла ошибка при попытке связать новое загруженное изображение и категорию',
                  );
                  return EMPTY;
                }),
              );
          }),
        )
      : of(null);

    const deleteImage$ = deleteImage
      ? this.categoryService.deleteImage(oldImage!).pipe(
          catchError(() => {
            this.throwErrorModal(
              'Произошла ошибка при попытке удалить старое изображение категории',
            );
            return EMPTY;
          }),
          concatMap(() => {
            return this.categoryService
              .setImageToCategory(category.id, '')
              .pipe(
                catchError(() => {
                  this.throwErrorModal(
                    'Произошла ошибка при попытке удаления связи старого изображения с категорией',
                  );
                  return EMPTY;
                }),
              );
          }),
        )
      : of(null);

    forkJoin([putCategory$, deleteImage$, loadImage$])
      .pipe(
        finalize(() => {
          this.awaitModal = false;
          this.cdr.markForCheck();
        }),
        tap(() => {
          this.successModal = true;
        }),
      )
      .subscribe();
  }

以防万一, throwErrorModal 是我的简单函数

 private throwErrorModal(content: string) {
    this.errorModalContent = content;
    this.errorModal = true;
  }
angular rxjs fork-join
1个回答
0
投票

forkJoin
等待所有可观察量发出值或错误并完成。
您正在使用
catchError
捕获来自 API 的任何错误,这就是
forkJoin
不取消订阅其他流的原因。 显示模式后,您可能会
throw
出现新错误,从而阻止其他流。

    const putCategory$ = this.categoryService.putCategory(category).pipe(
      catchError((response: any) => {
        if (response.error.info == 'NAME_EXISTS') {
          this.throwErrorModal(
            'Категория с таким названием уже существует. Измените название и попробуйте снова.',
          );
        } else {
          this.throwErrorModal(
            'Произошла ошибка при попытке обновить категорию',
          );
        }
        throw new Error("error message")
      }),
    );

请记住,使用

forkJoin
,3 个 API 调用将异步执行,因此您无法知道其中一个调用是否先于另一个调用完成(或出错)。如果您使用它,可能会出现这样的情况:
deleteImage$
loadImage$
putCategory$
有机会抛出错误之前完成。
因此,如果其他可观察量需要依赖于
putCategory$
的结果,您可以通过管道传输后者,并在
forkJoin
:
 中返回前者的 
switchMap

putCategory$.pipe(
  // Here `putCategory` has done its job
  switchMap( () => forkJoin([deleteImage$, loadImage$])),
  // Here the other observables have completed and have been executed asynchronously
  // But only if putCategory hasn't thrown any errors
  finalize(() => {
    this.awaitModal = false;
    this.cdr.markForCheck();
  }),
  tap(() => {
    this.successModal = true;
  }),
)

© www.soinside.com 2019 - 2024. All rights reserved.