如何在使用订阅的嵌套 for 循环中重构 HttpRequests?
How to refactor HttpRequests in nested for-loops that use subscribe?
我们有一个与前端无关的 REST-API,这意味着它总是将 IRI 发送到它的嵌套资源。因此,要检索一些数据,您总是必须进行多次 http 调用(首先获取父资源,然后获取其子资源等)
所以每个国家都有一个链接条目列表。每个条目都链接到一个产品,该产品具有指向其类别资源的 IRI。
export interface Country {
countryId: number;
name: string;
code: string;
projects: string[]; //contains an array of IRIs for the project resources
entries: string[];
}
export interface Entry {
entryId: number,
country: string,
information: string,
strategy: string,
action: string,
user: string,
product: string,
salesStatus1: string,
salesStatus2: string,
salesStatus3: string,
salesStatus4: string,
salesStatus5: string,
}
export interface Product {
productId: number,
productName: string,
sharepointId: string,
category: string,
plmId: string,
productStatus1: string,
productStatus2: string,
productStatus3: string,
productStatus4: string,
productStatus5: string,
productComponents: string[]
}
export interface Category {
categoryId: number,
name: string,
children: string[]
}
export class Node {
children: Node[] = [];
name: string;
isProduct: boolean;
}
因此,为了使用显示导航树所需的所有数据,我编写了以下代码:
ngOnInit() {
let nodes: Node[] = new Array<Node>();
this.countriesService.getAll()
.subscribe(
(countries) => {
for (let country of countries) {
let countryNode = new Node();
countryNode.name = country.name;
countryNode.isProduct = false;
for (let entryUrl of country.entries) {
this.entriesService.getByUrl(entryUrl).subscribe(
(entry) => {
this.productsService.getByUrl(entry.product).subscribe(
(product) => {
this.categoryService.getByUrl(product.category).subscribe(
(category) => {
let categoryNode = new Node();
categoryNode.name = category.name;
categoryNode.isProduct = true;
countryNode.children.push(categoryNode);
for (let childrenUrl of category.children) {
this.categoryService.getByUrl(childrenUrl).subscribe(
(childCategory) => {
let categoryChildNode = new Node();
categoryChildNode.name = childCategory.name;
categoryChildNode.isProduct = false;
categoryNode.children.push(categoryChildNode);
}
)
}
}
)
}
)
}
)
}
nodes.push(countryNode);
}
this.dataChange.next(nodes);
}
);
}
然而,由于我是 Angular 和 rxjs 的新手,我在“等待”直到所有调用完成并且所有数据(因为它是异步的)都存在(因此导航树总是未命中)时遇到问题元素)。像这样链接也是一种丑陋和不好的做法。所以我想重构
rxjs-methods 的代码,但是我完全不知道如何开始使用它,因为在检索数据之后我必须再次迭代它以获得嵌套的资源 IRI,并且还必须为树导航创建 Node 对象。
你能给我一些关于如何重构代码的帮助吗?
不确定这是否有帮助,我将请求与 rxjs 运算符结合起来。
this.countriesService.getAll()
.pipe(
map((cs) => forkJoin(cs.map(c => {
const countryNode = new Node();
countryNode.name = c.name;
countryNode.isProduct = false;
return forkJoin(c.entries.map(entryUrl => this.entriesService.getByUrl(entryUrl)))
.pipe(
switchMap(entries => forkJoin(entries.map(entry => this.productsService.getByUrl(entry.product)))),
switchMap(products => forkJoin(products.map(product => this.categoryService.getByUrl(product.category)))),
switchMap(categories => forkJoin(categories.map(category => {
const categoryNode = new Node();
categoryNode.name = category.name;
categoryNode.isProduct = true;
return forkJoin(category.children.map(childrenUrl => this.categoryService.getByUrl(childrenUrl)))
.pipe(
map(cc => {
categoryNode.children = cc.map(childCategory => {
const categoryChildNode = new Node();
categoryChildNode.name = childCategory.name;
categoryChildNode.isProduct = false;
return categoryChildNode;
});
return categoryNode;
})
);
}))),
map(categoryNodes => {
countryNode.children = categoryNodes;
return countryNode;
})
);
})))
).subscribe(countryNodes => {
this.dataChange.next(countryNodes)
});
我们有一个与前端无关的 REST-API,这意味着它总是将 IRI 发送到它的嵌套资源。因此,要检索一些数据,您总是必须进行多次 http 调用(首先获取父资源,然后获取其子资源等) 所以每个国家都有一个链接条目列表。每个条目都链接到一个产品,该产品具有指向其类别资源的 IRI。
export interface Country {
countryId: number;
name: string;
code: string;
projects: string[]; //contains an array of IRIs for the project resources
entries: string[];
}
export interface Entry {
entryId: number,
country: string,
information: string,
strategy: string,
action: string,
user: string,
product: string,
salesStatus1: string,
salesStatus2: string,
salesStatus3: string,
salesStatus4: string,
salesStatus5: string,
}
export interface Product {
productId: number,
productName: string,
sharepointId: string,
category: string,
plmId: string,
productStatus1: string,
productStatus2: string,
productStatus3: string,
productStatus4: string,
productStatus5: string,
productComponents: string[]
}
export interface Category {
categoryId: number,
name: string,
children: string[]
}
export class Node {
children: Node[] = [];
name: string;
isProduct: boolean;
}
因此,为了使用显示导航树所需的所有数据,我编写了以下代码:
ngOnInit() {
let nodes: Node[] = new Array<Node>();
this.countriesService.getAll()
.subscribe(
(countries) => {
for (let country of countries) {
let countryNode = new Node();
countryNode.name = country.name;
countryNode.isProduct = false;
for (let entryUrl of country.entries) {
this.entriesService.getByUrl(entryUrl).subscribe(
(entry) => {
this.productsService.getByUrl(entry.product).subscribe(
(product) => {
this.categoryService.getByUrl(product.category).subscribe(
(category) => {
let categoryNode = new Node();
categoryNode.name = category.name;
categoryNode.isProduct = true;
countryNode.children.push(categoryNode);
for (let childrenUrl of category.children) {
this.categoryService.getByUrl(childrenUrl).subscribe(
(childCategory) => {
let categoryChildNode = new Node();
categoryChildNode.name = childCategory.name;
categoryChildNode.isProduct = false;
categoryNode.children.push(categoryChildNode);
}
)
}
}
)
}
)
}
)
}
nodes.push(countryNode);
}
this.dataChange.next(nodes);
}
);
}
然而,由于我是 Angular 和 rxjs 的新手,我在“等待”直到所有调用完成并且所有数据(因为它是异步的)都存在(因此导航树总是未命中)时遇到问题元素)。像这样链接也是一种丑陋和不好的做法。所以我想重构 rxjs-methods 的代码,但是我完全不知道如何开始使用它,因为在检索数据之后我必须再次迭代它以获得嵌套的资源 IRI,并且还必须为树导航创建 Node 对象。
你能给我一些关于如何重构代码的帮助吗?
不确定这是否有帮助,我将请求与 rxjs 运算符结合起来。
this.countriesService.getAll()
.pipe(
map((cs) => forkJoin(cs.map(c => {
const countryNode = new Node();
countryNode.name = c.name;
countryNode.isProduct = false;
return forkJoin(c.entries.map(entryUrl => this.entriesService.getByUrl(entryUrl)))
.pipe(
switchMap(entries => forkJoin(entries.map(entry => this.productsService.getByUrl(entry.product)))),
switchMap(products => forkJoin(products.map(product => this.categoryService.getByUrl(product.category)))),
switchMap(categories => forkJoin(categories.map(category => {
const categoryNode = new Node();
categoryNode.name = category.name;
categoryNode.isProduct = true;
return forkJoin(category.children.map(childrenUrl => this.categoryService.getByUrl(childrenUrl)))
.pipe(
map(cc => {
categoryNode.children = cc.map(childCategory => {
const categoryChildNode = new Node();
categoryChildNode.name = childCategory.name;
categoryChildNode.isProduct = false;
return categoryChildNode;
});
return categoryNode;
})
);
}))),
map(categoryNodes => {
countryNode.children = categoryNodes;
return countryNode;
})
);
})))
).subscribe(countryNodes => {
this.dataChange.next(countryNodes)
});