Javascript RxJS:将对象键映射到可观察对象

Javascript RxJS:将对象键映射到可观察对象,javascript,typescript,rxjs,observable,Javascript,Typescript,Rxjs,Observable,我有一个向用户显示问题的应用程序。 问题草稿从SharePoint列表中加载。每个草稿都包含一个键,用于从另一个SharePoint列表加载对问题的正确回答。下面是我目前如何实现它的: interface QuestionDraft { title: string; responseKey: string; } interface Question { title: string; responses: string[]; } const drafts: QuestionDr

我有一个向用户显示问题的应用程序。 问题草稿从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)
    );
}
接口问题草稿{
标题:字符串;
响应键:字符串;
}
接口问题{
标题:字符串;
答复:字符串[];
}
常量草稿:问题草稿[]=[];
常量问题:问题[]=[];
//存根
私有getDrafts():可观察{
退票(汇票);
}
//存根
私有getResponses(键:字符串):可观察{
返回(键,键,键);
}
main():void{
getDrafts()。订阅(
数据=>{
常量res:string[]=[];
getResponses(data.responseKey).订阅(
d=>res.push(d),
error=>console.error(错误),
()=>questions.push({
标题:data.title,
答复:res
})
);
},error=>console.error(错误),
()=>console.log(问题)
);
}

此解决方案工作正常,但我认为
main()
中的代码看起来很凌乱。有没有更简单的方法来做同样的事情,例如使用
mergeMap
或类似的东西?

您可以尝试使用
flatMap
使它更干净。


如果您使用RxJS版本6,则必须使用pipe()方法并将flatMap转换为mergeMap

在rxjs 6中,@emcee22的示例如下:

this.getDrafts()
 .pipe(
   .mergeMap(function(x){return functionReturningObservableOrPromise(x)}),
   .mergeMap(...ad infinitum)
 ).subscribe(...final processing)

您可以使用
mergeMap
映射到新的可观察对象,并使用
toArray
收集阵列中发出的值。使用
catchError
处理流中的错误,并映射到其他可观察到的错误

此代码的工作方式与您的代码相同,它包含所有问题,直到
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; })
请记住,最后一个数组中的
问题
的顺序不一定与进入的
草稿
的顺序相同。顺序取决于
getResponses
Observable完成特定
draft
的速度。(这与当前代码的行为相同)

为确保
问题
的顺序与
草稿
的顺序相同,您可以使用
concatMap
而不是
mergeMap
。但这可能会减慢任务的整体执行,因为下一个
草稿
的响应将仅在上一个
草稿
的响应完成后获取

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; })