为了确保错误不会完成外部可观察量,我采用的常见 rxjs 效果模式是:
public saySomething$: Observable<Action> = createEffect(() => {
return this.actions.pipe(
ofType<AppActions.SaySomething>(AppActions.SAY_SOMETHING),
// Switch to the result of the inner observable.
switchMap((action) => {
// This service could fail.
return this.service.saySomething(action.payload).pipe(
// Return `null` to keep the outer observable alive!
catchError((error) => {
// What can I do with error here?
return of(null);
})
)
}),
// The result could be null because something could go wrong.
tap((result: Result | null) => {
if (result) {
// Do something with the result!
}
}),
// Update the store state.
map((result: Result | null) => {
if (result) {
return new AppActions.SaySomethingSuccess(result);
}
// It would be nice if I had access the **error** here.
return new AppActions.SaySomethingFail();
}));
});
请注意,我在内部可观察量上使用catchError
,以便在底层网络调用失败时保持外部可观察量处于活动状态(service.saySomething(action.payload)
(:
catchError((error) => {
// What can I do with error here?
return of(null);
})
随后的tap
和map
运算符通过允许null
在其签名中容纳这一点,即(result: Result | null)
.但是,我丢失了错误信息。最终,当最终map
方法返回时new AppActions.SaySomethingFail();
我丢失了有关错误的任何信息。
如何在整个管道中保留错误信息,而不是在捕获时丢失错误信息?
正如评论中所建议的,您应该使用类型保护功能
不幸的是,我无法在代码段中运行打字稿,所以我评论了类型
const { of, throwError, operators: {
switchMap,
tap,
map,
catchError
}
} = rxjs;
const actions = of({payload: 'data'});
const service = {
saySomething: () => throwError(new Error('test'))
}
const AppActions = {
}
AppActions.SaySomethingSuccess = function () {
}
AppActions.SaySomethingFail = function() {
}
/* Type guard */
function isError(value/*: Result | Error*/)/* value is Error*/ {
return value instanceof Error;
}
const observable = actions.pipe(
switchMap((action) => {
return service.saySomething(action.payload).pipe(
catchError((error) => {
return of(error);
})
)
}),
tap((result/*: Result | Error*/) => {
if (isError(result)) {
console.log('tap error')
return;
}
console.log('tap result');
}),
map((result/*: Result | Error*/) => {
if (isError(result)) {
console.log('map error')
return new AppActions.SaySomethingFail();
}
console.log('map result');
return new AppActions.SaySomethingSuccess(result);
}));
observable.subscribe(_ => {
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>
我不会尝试在整个管道中保留错误信息。相反,你应该把你的成功管道(tap
,map
(与你的错误管道(catchError
(分开,将所有运算符添加到他们应该实际使用的结果的可观察量中,即你的内在可观察量。
public saySomething$: Observable<Action> = createEffect(() => {
return this.actions.pipe(
ofType<AppActions.SaySomething>(AppActions.SAY_SOMETHING),
switchMap((action) => this.service.saySomething(action.payload).pipe(
tap((result: Result) => {
// Do something with the result!
}),
// Update the store state.
map((result: Result) => {
return new AppActions.SaySomethingSuccess(result);
}),
catchError((error) => {
// I can access the **error** here.
return of(new AppActions.SaySomethingFail());
})
)),
);
});
这样,tap
和map
只会在this.service.saySomething
的成功结果上执行。将所有错误副作用和错误映射移到catchError
中。