等待多个可观察对象(并行)以角度效果完成

时间:2019-03-11 20:55:16

标签: angular observable ngrx-effects switchmap

我正在写一个效果,该效果需要几个单独的服务调用(返回为可观察值)的结果才能完成。第一个服务调用必须在3个以上(可以是异步的)之前完成,然后再建立操作列表。我有它的工作,但感觉像是不必要的嵌套。

@Effect() loadMyData$: Observable<any> = this.actions$.pipe(
    ofType(fromMyData.LOAD_DATA),
    switchMap((action: fromMyData.Load) => {
        return this.dataService.openMyData(action.payload).pipe(
            switchMap(() => this.dataService.getShapes()),
            switchMap(shapeData => {
                return this.dataService.getCircles().pipe(
                    switchMap((circleData) => {
                        return this.dataService.getTriangles().pipe(
                            switchMap((triangleData) => {
                                const flatMyDataWithReferences: any = {
                                    triangleName: triangleData.name,
                                    shapeName: shapeData.name
                                };
                                return [
                                    new fromShapes.Load(),
                                    new fromBalls.Load(),
                                    new fromCircles.LoadListSuccess(
                                        this.organizeCircles(circleData)),
                                    new fromMyData.LoadSuccess(flatMyDataWithReferences),
                                    new fromUi.AddMessage({
                                        type: MessageType.Success, message: 'Successfully loaded my data ' +
                                            shapeData.name +
                                            ' from: ' + action.payload
                                    })
                                ];
                            }),
                            catchError((err) => this.myDataLoadErrorEvents(err))
                        );
                    }),
                    catchError((err) => this.myDataLoadErrorEvents(err))
                );
            }),
            catchError((err) => this.myDataLoadErrorEvents(err))
        );
    }),
    catchError((err) => this.myDataLoadErrorEvents(err))
);

基本上,在我的示例代码中,一旦我调用了dataService.openMyData并从中返回,我想并行进行以下调用:

  • dataService.getShapes
  • dataService.getCircles
  • dataService.getTriangles

完成所有操作后,我想在我的操作数组中使用其返回的数据放入return [new etc...]中以包装效果。

希望某人拥有比这丑陋(且不必要)的缩进方式更优雅的方式来处理3个中间服务调用...

我环顾四周,发现有些人正在使用forkJoin等待多个可观察对象的结果,但是看来他们不能使用该forkJoin可观察对象的结果作为操作的回报。例如,下面的代码告诉我,我最终并没有创建可观察的对象,而这正是我的效果所要求的。

@Effect() loadMyData$: Observable<any> = this.actions$.pipe(
    ofType(fromMyData.LOAD_DATA),
    switchMap((action: fromMyData.Load) => {
        return this.dataService.openMyData(action.payload).pipe(
            switchMap(() => {
                return forkJoin(
                        this.dataService.getShapes(),
                        this.dataService.getCircles(),
                        this.dataService.getTriangles()
                    ).pipe(
                        map(joinResult => {
                            const [shapeData, circleData, triangleData] = joinResult;
                            const flatMyDataWithReferences: any = {
                                triangleName: triangleData.name,
                                shapeName: shapeData.name
                            };
                            return [
                                new fromShapes.Load(),
                                new fromBalls.Load(),
                                new fromCircles.LoadListSuccess(
                                    this.organizeCircles(circleData)),
                                new fromMyData.LoadSuccess(flatMyDataWithReferences),
                                new fromUi.AddMessage({
                                    type: MessageType.Success, message: 'Successfully loaded my data ' +
                                        shapeData.name +
                                        ' from: ' + action.payload
                                })
                            ];
                        })
                    );
            }),
            catchError((err) => this.myDataLoadErrorEvents(err))
        );
    }),
    catchError((err) => this.myDataLoadErrorEvents(err))
);

2 个答案:

答案 0 :(得分:2)

使用forkJoin可以使用结果,而无需知道:

forkJoin(
    this.dataService.getShapes(),
    this.dataService.getCircles(),
    this.dataService.getTriangles()
).pipe(
    map(res => {
         // Here you can use the result. That result is an array of last emitted value for each observable. The order is the same that you declare in observable array.
        const [shapes, circles, triangles] = res;
     })
);

要考虑的重要一件事是,如果请求之一失败,则您将不会收到任何值,应正确捕获它。

这里可以查看更多信息forkJoin

答案 1 :(得分:1)

1。使用forkJoin等待多个可观察对象完成

事实证明,我的问题需要两个重要的解决方案,以使其能够作为可观察的行为的正确流,这就是效果作为回报所需要的。第一部分是@llsanchez响应-使用return forkJoin().pipe(map(response => response.stuff));形式以forkJoinpipemap是正确的顺序来完成效果。

2。根据您的需求,使用mapmergeMap返回效果中的可观察动作

要使某件事情具有多个结果动作(在我的示例中具有此效果),才能正常工作,您必须将map运算符替换为mergeMap,如下所示:

@Effect() loadMyData$: Observable<any> = this.actions$.pipe(
    ofType(fromMyData.LOAD_DATA),
    switchMap((action: fromMyData.Load) => {
        return this.dataService.openMyData(action.payload).pipe(
            switchMap(() => {
                return forkJoin(
                        this.dataService.getShapes(),
                        this.dataService.getCircles(),
                        this.dataService.getTriangles()
                    ).pipe(
                        mergeMap(joinResult => {
                            const [shapeData, circleData, triangleData] = joinResult;
                            const flatMyDataWithReferences: any = {
                                triangleName: triangleData.name,
                                shapeName: shapeData.name
                            };
                            return [
                                new fromShapes.Load(),
                                new fromBalls.Load(),
                                new fromCircles.LoadListSuccess(
                                    this.organizeCircles(circleData)),
                                new fromMyData.LoadSuccess(flatMyDataWithReferences),
                                new fromUi.AddMessage({
                                    type: MessageType.Success, message: 'Successfully loaded my data ' +
                                        shapeData.name +
                                        ' from: ' + action.payload
                                })
                            ];
                        })
                    );
            }),
            catchError((err) => this.myDataLoadErrorEvents(err))
        );
    }),
    catchError((err) => this.myDataLoadErrorEvents(err))
);

总而言之,要在效果中返回正确的操作流:

要使用效果返回单个动作,请使用map,格式如下:

return forkJoin().pipe(map(response => response.action))

要使用效果返回多个动作,请使用mergeMap,格式如下:

return forkJoin().pipe(mergeMap(response => [response.action1, response.action2]))