RxJS: получение множественного ответа

#angular #rxjs #observable #reactive-programming

#angular #rxjs #наблюдаемый #реактивное программирование

Вопрос:

У меня есть «вложенные» запросы, создание команды и загрузка аватара команды, где второй зависит от первого и должен быть отправлен, только если аватар не равен нулю (я уже сделал это с помощью оператора фильтра). Что мне нужно сейчас, так это получить доступ к обоим ответам в методе подписки.

 this.team.createTeam(teamRequest)
    .pipe(
        filter(() => avatar),
        flatMap(next => this.team.uploadLogo(avatar, next.body.uuid)
    ).subscribe(responses => {
        // so, I want response from both createTeam and uploadLogo in responses
});
  

Ответ №1:

Вы могли бы передать map оператор во внутренний запрос и отправить оба ответа. Попробуйте следующее

 this.team.createTeam(teamRequest)
  .pipe(
    filter(() => avatar),
    flatMap(next => 
      this.team.uploadLogo(avatar, next.body.uuid).pipe(
        map(res => ({ avatar: res, team: next }))
      )
    )
  ).subscribe(responses => {
      // responses.avatar: response from `this.team.uploadLogo(avatar, next.body.uuid)` 
      // responses.team: response from `this.team.createTeam(teamRequest)` 
  });
  

Я вернул объект для иллюстрации. Вы можете вернуть его в любой форме в соответствии с вашими требованиями. Например. в виде массива map(res => [ next, res ])) .

Обновление: iif функция вместо filter оператора

Если вы все еще хотите подписаться на источник, наблюдаемый при сбое filter условия, самый быстрый способ, который я мог придумать, — это отказаться от filter оператора и вместо этого использовать iif функцию. Попробуйте следующее

 const upload = (avatar, team): Observable<any> => {
  return this.team.uploadLogo(avatar, next.body.uuid).pipe(
    map(res => ({ avatar: avatar, team: team }))
  );
};

iif(() =>
  !!avatar,
  this.team.createTeam(teamRequest).pipe(flatMap(next => upload(avatar, next.body.uuid))),
  this.team.createTeam(teamRequest)
).subscribe(
  responses => {
    // if `avatar` is null
    // responses: response from `this.team.createTeam(teamRequest)`
    // or
    // if `avatar` is non-null
    // responses.avatar: response from `this.team.uploadLogo(avatar, next.body.uuid)` 
    // responses.team: response from `this.team.createTeam(teamRequest)` 
  }
);
  

Обновление: проверьте avatar внутри flatMap

Как предложил @bryan60, вот более чистый код, который не использует ни filter ни iif . Но скорее проверяет avatar внутри flatMap и возвращает of(next) значение null.

 this.team.createTeam(teamRequest).pipe(
  flatMap(next => {
    if (!!avatar) {
      return this.team.uploadLogo(avatar, next.body.uuid).pipe(
        map(res => ({ avatar: res, team: next }))
      );
    }
    return of(next);
  })
).subscribe(responses => {
    // if `avatar` is null
    // responses: response from `this.team.createTeam(teamRequest)`
    // or
    // if `avatar` is non-null
    // responses.avatar: response from `this.team.uploadLogo(avatar, next.body.uuid)` 
    // responses.team: response from `this.team.createTeam(teamRequest)` 
});
  

Комментарии:

1. Псевдоним flatMap устарел, лучше использовать mergeMap .

2. Кстати, если аватар равен нулю и фильтр не работает, мне все равно нужно получить ответ от createTeam. Как я могу это сделать??

3. Да, я тоже думал об этом. Спасибо вам еще раз.

4. удалите условие фильтра.

5. flatMap в коде упоминается устаревание github.com/ReactiveX/rxjs/blob / … мой локальный vs-код также отображает это сообщение.