英文:
How to catch @ngrx/effects errors properly?
问题
我知道这个问题已经被问过很多次,但请记住我的特定问题,因为我找不到能够正确解决它的方法。
我有一个 effect
,它应该按特定顺序执行多个 HTTP 请求 - 调用 1、调用 2、调用 3。我希望能够捕获任何错误,无论在整个链中的哪个地方抛出。我希望保持 rxjs
操作符的结构尽可能扁平,以避免嵌套的混乱代码。
以下是示例代码:
getMockDataEffect$ = createEffect(
() => this.actions$.pipe(
ofType(ApiGetMockData),
concatMap(() => {
return this.mockApi.mock1().pipe(
concatMap(() => {
return this.mockApi.mock2();
}),
concatMap(() => {
return this.mockApi.mock3();
}),
map(res => ApiSuccess({ data: res })),
catchError(error => of(ApiError({ error }))),
)
}
)
)
)
在上面的示例中,如果在 mock2
或 mock3
中发生错误,它将被成功捕获。然而,如果在 mock1
中发生错误,错误将完全不会被捕获。
我的问题是:我应该如何构建我的 effect,以使我的 catchError
操作符可以捕获发生在 mock1
、mock2
或 mock3
中的任何错误,而不会完成 effect 的可观察对象?也就是说,如果发生错误,我应该能够分派动作并在之后成功运行 effect。
这里有一个StackBlitz演示。
英文:
I know this question has been asked several times, but keep in mind my specific issue, because I couldn't find anything that solves it properly.
I have an effect
that should perform multiple HTTP requests in a specific order - call 1, call 2, call 3. I want to be able to catch any error that is being thrown throughout the chain. I want to keep the structure of the rxjs
operators as flat as possible to avoid nested spaghetti code.
Here's sample code:
getMockDataEffect$ = createEffect(
() => this.actions$.pipe(
ofType(ApiGetMockData),
concatMap(() => {
return this.mockApi.mock1().pipe(
concatMap(() => {
return this.mockApi.mock2();
}),
concatMap(() => {
return this.mockApi.mock3();
}),
map(res => ApiSuccess({ data: res })),
catchError(error => of(ApiError({ error }))),
)
}
)
)
)
In the example given above, if an error occurs in mock2
or mock3
, it would be successfully caught. However, if one occurs in mock1
, the error won't be caught at all.
My question is: how do I structure my effect in such a way that my catchError
operator would catch any error occurring in mock1
, mock2
or mock3
, without completing the effect's observable? Meaning, if an error occurs, I should be able to dispatch the action and run the effect successfully after that.
Here's a StackBlitz demo.
答案1
得分: 2
我认为你的示例很好。
问题在于 throw
,因为我认为这是用于JavaScript执行的,它只会停止因为没有被捕获。
一个现实的情况是函数以Observable格式返回错误,为此你必须使用 throwError
。当HTTP请求失败时,它将成为一个错误的Observable。
所以要使你的情况工作,将 mockapi.service.ts
更改为以下内容:
import { Injectable } from '@angular/core';
import { of, throwError } from 'rxjs';
import { map, tap } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class MockApiService {
mock1() {
//return throwError('e1');
return of('mock1');
}
mock2() {
// return throwError('e2');
return of('mock2');
}
mock3() {
// return throwError('e3');
return of('mock3');
}
}
取消注释任何函数上的 throwError
来模拟它已经出现了错误。
英文:
I think your example is good.
The issue is the throw
because I think this is for JavaScript execution and it just stops because it is not being caught.
A realistic scenario would be that the functions return an error in an Observable format and for this you have to use throwError
. When an http request fails, it will be an error observable.
So to get your situation working, change mockapi.service.ts
to the following:
import { Injectable } from '@angular/core';
import { of, throwError } from 'rxjs';
import { map, tap } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class MockApiService {
mock1() {
//return throwError('e1');
return of('mock1');
}
mock2() {
// return throwError('e2');
return of('mock2');
}
mock3() {
// return throwError('e3');
return of('mock3');
}
}
Uncomment any of the throwError
s on whatever function to simulate it has errored.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论