1

我正在编写一个效果,该效果需要几个单独的服务调用的结果(作为可观察对象返回),然后才能完成它。第一个服务调用必须在另外 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 来等待多个 observable 的结果,但似乎他们不能使用该 forkJoin observable 的结果作为操作的返回值。例如,下面的这段代码告诉我,我最终没有创建一个 observable,这是我的效果所需要的。

@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))
);
4

2 回答 2

3

使用 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

于 2019-03-11T21:15:02.160 回答
2

1.forkJoin用于等待多个 Observables 完成

事实证明,我的问题需要两个重要的解决方案才能使其作为适当的可观察动作流工作,这就是效果作为回报所需要的。第一部分是@llsanchez 响应 - 使用return forkJoin().pipe(map(response => response.stuff));表单来完成效果,其中forkJoin, thepipe和 themap是正确的顺序。

2. 根据你的需要,在你的 Effect 中使用mapmergeMap返回 Action Observable(s)

为了使事情在具有多个结果操作(我的示例具有)的效果中正常工作,您必须将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))
);

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

要在 Effect 中返回单个动作,请使用map,如下形式:

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

要在 Effect 中返回多个 Action,请使用mergeMap,如以下形式:

return forkJoin().pipe(mergeMap(response => [response.action1, response.action2]))
于 2019-03-12T14:49:39.133 回答