我有一个向用户显示问题的应用程序。 问题的草稿从SharePoint列表中加载。每个草稿都包含一个密钥,该密钥用于从另一个SharePoint列表中加载对问题的正确答案。这是我目前的实现方式:
interface QuestionDraft {
title: string;
responseKey: string;
}
interface Question {
title: string;
responses: string[];
}
const drafts: QuestionDraft[] = [];
const questions: Question[] = [];
// stub
private getDrafts(): Observable<QuestionDraft> {
return from(drafts);
}
// stub
private getResponses(key: string): Observable<string> {
return of(key, key, key);
}
main(): void {
getDrafts().subscribe(
data => {
const res: string[] = [];
getResponses(data.responseKey).subscribe(
d => res.push(d),
error => console.error(error),
() => questions.push({
title: data.title,
responses: res
})
);
}, error => console.error(error),
() => console.log(questions)
);
}
此解决方案效果很好,但我认为main()
中的代码看起来很混乱。有没有更简单的方法来完成相同的事情,例如使用mergeMap
或类似的方法?
答案 0 :(得分:1)
您可以使用mergeMap
映射到新的Observable并使用toArray
收集数组中发出的值。使用catchError
处理流中的错误,并映射到错误的替代Observable。
此代码将与您的代码一样工作,所发出的问题数组包含所有问题,直到getDrafts
引发错误并排除getResponses
引发错误的问题为止。
getDrafts().pipe(
mergeMap(draft => getResponses(draft.responseKey).pipe(
toArray(),
map(responses => ({ title: draft.title, responses } as Question)),
catchError(error => { console.error(error); return EMPTY; })
)),
catchError(error => { console.error(error); return EMPTY; }),
toArray()
).subscribe(qs => { console.log(qs); questions = qs; })
请记住,最终数组中的questions
不一定与进入的drafts
顺序相同。该顺序取决于getResponses
可观察对象完成的速度特定的draft
。 (这与您当前的代码相同)
要确保questions
与drafts
的顺序相同,可以使用concatMap
代替mergeMap
。但这可能会减慢任务的整体执行速度,因为下一个draft
的响应只有在前一个draft
的响应完成之后才能获取。
答案 1 :(得分:0)
您可以尝试使用flatMap
使其更整洁。
RxJs Observables nested subscriptions?
this.getDrafts()
.flatMap(function(x){return functionReturningObservableOrPromise(x)})
.flatMap(...ad infinitum)
.subscribe(...final processing)
答案 2 :(得分:0)
如果使用RxJS版本6,则必须使用pipe()方法并将flatMap转换为mergeMap。
在rxjs 6中,@ emcee22的示例如下所示:
this.getDrafts()
.pipe(
.mergeMap(function(x){return functionReturningObservableOrPromise(x)}),
.mergeMap(...ad infinitum)
).subscribe(...final processing)