如何从失败的 forkJoin 请求中获取数据?
How to get data from failed forkJoin request?
使用 Angular
Rxjs
和 ngrx
我有一个调度 4 API 的操作,我正在执行以下操作 =>
@Effect()
getAllModels$ = this.actions$.pipe(
ofType<featureActions.GetAllModelsRequest>(featureActions.ActionTypes.GetAllModelsRequest),
switchMap((action) =>
forkJoin([
this.dataService.GetAllModelFromServer(),
this.dataService.GetAllModelFromHost(),
this.dataService.GetAllModelFromCache(),
this.dataService.GetAllModelFromPreference(),
]).pipe(
map(
([server, host, cache, preference]) =>
new featureActions.GetAllModelsSuccess({
//...
})
),
catchError((error: HttpErrorResponse) => {
return of(new featureActions.GetAllModelsFailed({ error: error.message }));
})
)
)
);
问题是,当其中一个 API 失败时,一切都失败了,我处于失败行动中。所有检索到的数据(在一个端点失败之前)都丢失了。
有没有办法获取 catchError
中检索到的数据,或者唯一的解决方案是将 api 一个接一个地链接起来?
您可以编写自己的 forkJoin
实现。这是一个源自原始 (https://github.com/ReactiveX/rxjs/blob/master/src/internal/observable/forkJoin.ts) 的简单示例:
export function forkJoin2(...args: any[]): Observable<any> {
const resultSelector = popResultSelector(args);
const { args: sources, keys } = argsArgArrayOrObject(args);
if (resultSelector) {
// deprecated path.
return forkJoinInternal(sources, keys).pipe(map((values: any[]) => resultSelector!(...values)));
}
return forkJoinInternal(sources, keys);
}
function forkJoinInternal(sources: ObservableInput<any>[], keys: string[] | null): Observable<any> {
return new Observable((subscriber) => {
const len = sources.length;
if (len === 0) {
subscriber.complete();
return;
}
const values = new Array(len);
let completed = 0;
let emitted = 0;
for (let sourceIndex = 0; sourceIndex < len; sourceIndex++) {
const source = innerFrom(sources[sourceIndex]);
let hasValue = false;
subscriber.add(
source.subscribe({
next: (value) => {
if (!hasValue) {
hasValue = true;
emitted++;
}
values[sourceIndex] = value;
},
error: (err) => { return subscriber.error({ error: err, values }) },
complete: () => {
completed++;
if (completed === len || !hasValue) {
if (emitted === len) {
subscriber.next(keys ? keys.reduce((result, key, i) => (((result as any)[key] = values[i]), result), {}) : values);
}
subscriber.complete();
}
},
})
);
}
});
}
注意,当发生错误时,您将返回错误以及值:
error: (err) => { return subscriber.error({ error: err, values }) }
我在这里找到了这个解决方案:https://medium.com/better-programming/rxjs-error-handling-with-forkjoin-3d4027df70fc
@Effect()
getAllModels$ = this.actions$.pipe(
ofType<featureActions.GetAllModelsRequest>(featureActions.ActionTypes.GetAllModelsRequest),
switchMap((action) =>
forkJoin([
this.dataService.GetAllModelFromServer().pipe(catchError(() => of({ data: [] }))),
this.dataService.GetAllModelFromHost().pipe(catchError(() => of({ data: [] }))),
this.dataService.GetAllModelFromCache().pipe(catchError(() => of({ data: [] }))),
this.dataService.GetAllModelFromPreference().pipe(catchError(() => of({ data: [] }))),
]).pipe(
map(
([server, host, cache, preference]) =>
new featureActions.GetAllModelsSuccess({
//...
})
),
catchError((error: HttpErrorResponse) => {
return of(new featureActions.GetAllModelsFailed({ error: error.message }));
})
)
)
);
使用 Angular
Rxjs
和 ngrx
我有一个调度 4 API 的操作,我正在执行以下操作 =>
@Effect()
getAllModels$ = this.actions$.pipe(
ofType<featureActions.GetAllModelsRequest>(featureActions.ActionTypes.GetAllModelsRequest),
switchMap((action) =>
forkJoin([
this.dataService.GetAllModelFromServer(),
this.dataService.GetAllModelFromHost(),
this.dataService.GetAllModelFromCache(),
this.dataService.GetAllModelFromPreference(),
]).pipe(
map(
([server, host, cache, preference]) =>
new featureActions.GetAllModelsSuccess({
//...
})
),
catchError((error: HttpErrorResponse) => {
return of(new featureActions.GetAllModelsFailed({ error: error.message }));
})
)
)
);
问题是,当其中一个 API 失败时,一切都失败了,我处于失败行动中。所有检索到的数据(在一个端点失败之前)都丢失了。
有没有办法获取 catchError
中检索到的数据,或者唯一的解决方案是将 api 一个接一个地链接起来?
您可以编写自己的 forkJoin
实现。这是一个源自原始 (https://github.com/ReactiveX/rxjs/blob/master/src/internal/observable/forkJoin.ts) 的简单示例:
export function forkJoin2(...args: any[]): Observable<any> {
const resultSelector = popResultSelector(args);
const { args: sources, keys } = argsArgArrayOrObject(args);
if (resultSelector) {
// deprecated path.
return forkJoinInternal(sources, keys).pipe(map((values: any[]) => resultSelector!(...values)));
}
return forkJoinInternal(sources, keys);
}
function forkJoinInternal(sources: ObservableInput<any>[], keys: string[] | null): Observable<any> {
return new Observable((subscriber) => {
const len = sources.length;
if (len === 0) {
subscriber.complete();
return;
}
const values = new Array(len);
let completed = 0;
let emitted = 0;
for (let sourceIndex = 0; sourceIndex < len; sourceIndex++) {
const source = innerFrom(sources[sourceIndex]);
let hasValue = false;
subscriber.add(
source.subscribe({
next: (value) => {
if (!hasValue) {
hasValue = true;
emitted++;
}
values[sourceIndex] = value;
},
error: (err) => { return subscriber.error({ error: err, values }) },
complete: () => {
completed++;
if (completed === len || !hasValue) {
if (emitted === len) {
subscriber.next(keys ? keys.reduce((result, key, i) => (((result as any)[key] = values[i]), result), {}) : values);
}
subscriber.complete();
}
},
})
);
}
});
}
注意,当发生错误时,您将返回错误以及值:
error: (err) => { return subscriber.error({ error: err, values }) }
我在这里找到了这个解决方案:https://medium.com/better-programming/rxjs-error-handling-with-forkjoin-3d4027df70fc
@Effect()
getAllModels$ = this.actions$.pipe(
ofType<featureActions.GetAllModelsRequest>(featureActions.ActionTypes.GetAllModelsRequest),
switchMap((action) =>
forkJoin([
this.dataService.GetAllModelFromServer().pipe(catchError(() => of({ data: [] }))),
this.dataService.GetAllModelFromHost().pipe(catchError(() => of({ data: [] }))),
this.dataService.GetAllModelFromCache().pipe(catchError(() => of({ data: [] }))),
this.dataService.GetAllModelFromPreference().pipe(catchError(() => of({ data: [] }))),
]).pipe(
map(
([server, host, cache, preference]) =>
new featureActions.GetAllModelsSuccess({
//...
})
),
catchError((error: HttpErrorResponse) => {
return of(new featureActions.GetAllModelsFailed({ error: error.message }));
})
)
)
);