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

时间:2019-06-02 08:57:03

标签: javascript typescript rxjs observable

我有一个向用户显示问题的应用程序。 问题的草稿从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或类似的方法?

3 个答案:

答案 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。 (这与您当前的代码相同)

要确保questionsdrafts的顺序相同,可以使用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)