嵌套mergeMap+forkJoin组合



我正在使用表单tool > feature > view的数据。换句话说,有工具,工具有特性,特性有视图。

在Angular 2(13)中,我使用了一个服务来处理http调用来获取数据。当应用启动时,解析器通过调用服务的setTools()方法触发服务的tools数组属性的设置。该方法应该通过获取工具来构建tools,然后用特性填充每个工具,每个工具都用视图填充,所有这些都通过对每个部分的嵌套http调用。

我发现了一个使用mergeMapforkJoin(来自rxjs)组合的实现,它在单个层上实现了这一点。然后,我在服务中实现了以下内容:

setTools(): Observable<Tool[]> {
return this.getTools().pipe(
mergeMap(tools =>
forkJoin<Tool[]>(
tools.map(tool =>
this.getFeatures(tool.id).pipe(
map(features => ({ ...tool, features })
)
)
)
),
tap<Tool[]>(tools => console.log(tools))
)
}

可以正常工作。工具被打印出来,每个工具包含其各自的特性。太棒了!

我天真地实现了以下操作来实现下一层填充,即视图:

setTools(): Observable<Tool[]> {
return this.getTools().pipe(
mergeMap(tools =>
forkJoin<Tool[]>(
tools.map(tool =>
this.getFeatures(tool.id).pipe(
mergeMap(features =>
forkJoin<Feature[]>(
features.map(feature =>
this.getViews(feature.id).pipe(
map(views => ({ ...feature, views })
)
)
)
),
map(features => ({ ...tool, features })
)
)
)
),
tap<Tool[]>(tools => console.log(tools))
)
}

但是,工具不再注销到控制台。为什么?我做错了什么?此外,如果有另一种方法来实现这一点,我将非常感谢输入。仅供参考,我对web开发相当陌生。

如果没有更多的代码/类型,我无法让你的例子工作,所以我稍微改变了方法,可能不能完全回答这个问题。使用mergeMap与mergeAll和to Array可以得到嵌套的结构。

setTools() {
return this.getTools().pipe(
mergeAll(),
mergeMap(tool =>
this.getFeatures(tool.id).pipe(
mergeAll(),
mergeMap(feature=>
this.getViews(feature.id).pipe(
map((views) => ({...feature, views }))
)
),
toArray(),
map((features)=>({...tool, features}))
)
),
toArray(),
);
}

参见stackblitz: https://stackblitz.com/edit/angular-ivy-ee1myv?file=src/app/app.component.ts

我刚刚把你的代码分成了几个单独的函数。它运行得很好对我来说一个极简主义者利用。基本没有变化…

embellishFeature(feature){
return this.getViews(feature.id).pipe(
map(views => ({...feature, views}))
);
}
embellishFeatures(features){
return forkJoin(features.map(v => this.embellishFeature(v)));
}
embellishTool(tool){
return this.getFeatures(tool.id).pipe(
mergeMap(v => this.embellishFeatures(v)),
map(features => ({...tool, features}))
);
}
embellishTools(tools){
return forkJoin(tools.map(v => this.embellishTool(v)));
}
setTools(): Observable<Tool[]> {
return this.getTools().pipe(
mergeMap(v => this.embellishTools(v)),
tap(tools => console.log(tools))
);
}

最新更新