我试图在我的解析器中返回一堆嵌套的forkjoins和normal订阅。为此,我尝试使用地图,但是我想我还没有完全掌握map / switchMaps / mergeMaps的概念。 我知道代码还没有返回UserResult,这是因为我还不知道如何将QuestionAnswers添加到UserResult中,但这与我当前的问题没有太大的区别。
我的目标是重写它,以便它返回可观察的结果。
(?<product>.*?)
我试图像这样重写它,但是它根本不起作用。我遇到了一些未定义的错误,但它们都指向管道的起点,没有具体说明。
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<UserResult> {
const questionAnswers = Array<QuestionAnswer>();
this.rs.getResult(this.auth.token, route.params['id']).subscribe(res => {
forkJoin(
this.quizs.getCategoriesQuiz(this.auth.token, res.quizId),
this.accs.getAccount(res.userId)
).subscribe(results => {
forkJoin(
this.accs.getUserDetails(results[1].access_token),
this.as.getAnswers(this.auth.token)
).subscribe(results2 => {
results[0].forEach(cat => {
this.cs
.getQuestionsCategory(this.auth.token, cat.id)
.subscribe(questions => {
results2[1]
.filter(ans => ans.userId === results[1].uid)
.forEach(a => {
const question = questions.find(q => q.id === a.questionId);
if (!isNullOrUndefined(question)) {
const category = results[0].find(
c => c.id === a.categoryId
);
const qa = new QuestionAnswer(question, a);
qa.category = category.name;
questionAnswers.push(qa);
}
});
});
});
});
});
});
}
编辑
引起我注意的是,点击result2后res [0]引起
无法读取未定义的属性“ 0”
我认为这与我对水龙头的使用不当有关,因为它在我尝试更改的订阅中运行良好。
EDIT2
我将代码拆分为较小的功能,如Kurt建议,但是我不确定如何将其与我用于类别的forEach结合使用。我也不知道应该在哪里创建最终的对象,该对象将以可观察的方式返回
const questionAnswers = Array<QuestionAnswer>();
let res;
let res2;
return this.rs.getResult(this.auth.token, route.params['id']).pipe(
map((res: Result) =>
forkJoin(
this.quizs.getCategoriesQuiz(this.auth.token, res.quizId),
this.accs.getAccount(res.userId)
)
),
tap(results => (res = results)),
map(results =>
forkJoin(
this.accs.getUserDetails(results[1].access_token),
this.as.getAnswers(this.auth.token)
)
),
tap(results2 => (res2 = results2)),
map(
res[0]
.forEach(cat => {
this.cs.getQuestionsCategory(this.auth.token, cat.id);
})
.map(questions =>
res2[1]
.filter(ans => ans.userId === res[1].uid)
.forEach(a => {
const question = questions.find(q => q.id === a.questionId);
if (!isNullOrUndefined(question)) {
const category = res[0].find(c => c.id === a.categoryId);
const qa = new QuestionAnswer(question, a);
qa.category = category.name;
questionAnswers.push(qa);
}
})
)
)
);
答案 0 :(得分:2)
所以...那是您那里的RxJS很大一部分。
首先,您不需要在RxJS运算符内进行订阅,而是将可观察对象链接在一起。
switchMap
和concatMap
用于将一个可观察的结果传递给另一个。
map
用于将值从一种结构转换为另一种结构(类似于同名数组函数的概念)。
forkJoin
组合了多个可观察对象,并在它们全部完成后返回一个结果。
在您甚至开始尝试整理代码之前,我建议您考虑考虑将每个步骤拆分为自己的功能。希望这将帮助您查看数据流并考虑依赖项在哪里。
我可以将您的原始示例转换为RxJS,但是在考虑每个步骤实际上试图实现的目标时却迷失了一部分。
我确定的是,您最终会得到一个类似这样的模式(出于这个演示的目的,我正在订阅-您将返回可观察的结果):
result: string;
ngOnInit() {
this.initialValue().pipe(
switchMap(result => this.forkJoinOne(result)),
switchMap(result => this.forkJoinTwo(result)),
switchMap(result => this.forkJoinThree(result)),
map(result => this.mapFour(result))
).subscribe(result => {
this.result = result;
});
}
private initialValue(): Observable<string> {
return of('zero');
}
private forkJoinOne(result: string): Observable<string[]> {
return forkJoin([
of(`${result} one`),
of('four')
]);
}
private forkJoinTwo(results: string[]): Observable<string[]> {
return forkJoin([
of(`${results[0]} two`),
of(`${results[1]} five`)
]);
}
private forkJoinThree(results: string[]): Observable<string[]> {
return forkJoin([
of(`${results[0]} three`),
of(`${results[1]} six`)
]);
}
private mapFour(results: string[]): string {
return results.join(' ');
}
每个可观察的步骤都已移入其自己的功能-这可以帮助您考虑需要输入什么数据和要输出什么数据-您正在有效地在每个步骤之间创建合同。
switchMap
只是一个可观察的对象,而建立了另一个。最后的map
将前面可观察到的输出转换为另一个值。
我在这里使用了字符串,希望可以简化跟踪数据流的过程。我建议从尝试理解我的简单示例开始,然后使用这些原理重新构建您的功能。
演示:https://stackblitz.com/edit/angular-eedbqg
我的版本在以下方面与您的版本大致保持一致:
初始值
this.rs.getResult(this.auth.token, route.params['id'])
forkJoinOne
所有fork联接都应传入数组或对象。我更喜欢传入对象的相对较新的方式,它指明了发射值的结构。 (forkJoin({ a: myObs })
返回{ a: value }
)。
forkJoin(
this.quizs.getCategoriesQuiz(this.auth.token, res.quizId),
this.accs.getAccount(res.userId)
)
forkJoinTwo
forkJoin(
this.accs.getUserDetails(results[1].access_token),
this.as.getAnswers(this.auth.token)
)
forkJoinThree
您将需要将此循环转换为可观察对象数组,并将其传递给forkJoin
。
results[0].forEach(cat => {
this.cs.getQuestionsCategory(this.auth.token, cat.id)
mapFour
您将需要整理地图。此处使用forEach
和filter
(数组函数)代替map
。
map(questions =>
res2[1]
.filter(ans => ans.userId === res[1].uid)
.forEach(a => {
const question = questions.find(q => q.id === a.questionId);
if (!isNullOrUndefined(question)) {
const category = res[0].find(c => c.id === a.categoryId);
const qa = new QuestionAnswer(question, a);
qa.category = category.name;
questionAnswers.push(qa);
}
})