RxJS: Отображение ключей объекта в наблюдаемые - PullRequest
0 голосов
/ 02 июня 2019

У меня есть приложение, в котором пользователям показываются вопросы. Черновики для вопросов загружаются из списка 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 ]

1 голос
/ 03 июня 2019

Вы можете использовать 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; })

Имейте в виду, что questions в конечном массиве не обязательно будет в том же порядке, что и входящий drafts. Порядок зависит от того, как быстро завершается getResponses Observable для конкретного draft. (Это то же поведение, что и ваш текущий код)

Чтобы убедиться, что questions будет в том же порядке, что и drafts, вы можете использовать concatMap вместо mergeMap. Но это может замедлить общее выполнение задачи, поскольку ответы на следующий draft будут выбраны только после того, как ответы на предыдущий draft завершены.

0 голосов
/ 02 июня 2019

Если вы используете RxJS версии 6, вы должны использовать метод pipe () и превратить flatMap в mergeMap.

в rxjs 6 будет выглядеть пример @ emcee22:

this.getDrafts()
 .pipe(
   .mergeMap(function(x){return functionReturningObservableOrPromise(x)}),
   .mergeMap(...ad infinitum)
 ).subscribe(...final processing)
0 голосов
/ 02 июня 2019

Вы можете попробовать и использовать flatMap, чтобы сделать его чище. RxJs Observables вложенные подписки?

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