问题在于,即使前一个查询失败,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;
}
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;
}),
)