RxJS Observable, одно сообщение об успехе с оператором concat

В контексте компонента Angular у меня есть 2 наблюдаемых.

Требования

  1. Я хочу выполнить оба последовательно.
  2. Если первое наблюдаемое не удалось, я не хочу запускать второе
  3. Если что-то потерпит неудачу, я хочу зарегистрировать одно сообщение об ошибке.
  4. Если оба успешны, я хочу зарегистрировать одно сообщение об успехе.

Подход

  • Я использую concat для достижения №1 и №2.
  • Я фиксирую №3 в уведомлении об ошибке подписки concat. Будет обработано только 1 уведомление об ошибке из-за concat.
  • № 4 — вот в чем проблема. Я не могу использовать next в подписке concat, так как она будет регистрировать сообщение об успехе для каждого наблюдаемого. Я могу справиться с этим в полном уведомлении о подписке concat, но обычно это не тот случай, когда вы справляетесь с успехом. Этот подход пахнет кодом.

Как лучше всего удовлетворить мои требования?

    getData1$ = this.myService.getData1();
    getData2$ = this.myService.getData2();
    
    constructor(private myService: MyService) {
      this.getAllData();
    }
    
    getAllData() {
      concat(this.getData1$, this.getData2$)
      .pipe(finalize(() => console.info('always called')))
      .subscribe(() => {
        error: console.info('one or more data fetches have had an error');
        complete: console.info('all data fetches have succeeded');
      });}
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
1
0
69
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Используйте concat , он будет выполняться последовательно один за другим, затем мы можем использовать toArray, который соберет все выбросы источника и выдаст их в виде массива, когда источник завершится.

getData1$ = this.myService.getData1();
getData2$ = this.myService.getData2();

constructor(private myService: MyService) {
  this.getAllData();
}

getAllData() {
  concat(this.getData1$, this.getData2$).pipe(toArray())
  .subscribe({
    next: (data: any) => console.info('success!'),
    error: () => console.info('one or more data fetches have had an error'),
    complete: () => console.info('all data fetches have succeeded'),
  });
}

Демо-версия Stackblitz

Привет, Нарен, спасибо за ответ. Однако решение в предоставленной демонстрации Stackblitz не отвечает этим требованиям. Вы можете увидеть, выдает ли одна из наблюдаемых ошибку, например, она не соответствует требованиям.

Fred2020 22.06.2024 14:28

@Fred2020, пожалуйста, поделитесь стекблицем с неудачным сценарием и тем, что нужно исправить, насколько я вижу, мой код соответствует вашим требованиям стекблиц с неудачным наблюдаемым

Naren Murali 22.06.2024 21:17

Попробуйте.... const arraySource = concat( of(1), throwError(new Error('Error')) ).pipe(toArray());

Fred2020 23.06.2024 13:25

@Fred2020 это работает stackblitz

Naren Murali 23.06.2024 15:26

Приношу извинения, это работает с добавленным обработчиком ошибок.

Fred2020 23.06.2024 21:35

А как насчет требования «Если первое наблюдаемое не работает, я не запускаю второе»? В вашем примере второй наблюдаемый объект, скорее всего, будет вызван, даже если он не подписан (HttpService создает горячие наблюдаемые объекты).

Liero 24.06.2024 10:43

@Liero Невозможно преобразовать завершенный API в неисправный API, это пример не всего API, но он будет работать, если вы работаете с вызовами API

Naren Murali 24.06.2024 10:45

С помощью следующего кода я достиг желаемого результата в Angular 18:

    concat(this.getData1$, this.getData2$)
      .pipe(takeUntil(this.destroy$)) // You dont need it, but it wouldnt hurt.
      .subscribe({
        next: (res) => {
          //This logs if a request is successful.
          console.info(res);
        },
        error: (err) => {
          //This logs if a request is NOT successful.
          console.info('Error');
        },
        complete: () => {
          //This logs if ALL requests are successful.
          console.info('Complete');
        },
      });

Это запустит Observables последовательно.
Если один из них потерпит неудачу, он зарегистрирует ошибку и остановится.
Если он пройдет, он зарегистрирует каждый ответ и зарегистрирует его в конце.
Не хватает только finalize, так как при подписке у меня возникли ошибки.

Итак, чем отличается ваш Кодекс?
Вместо .subscribe(() => {...}) я использую .subscribe({...})

Кстати, это то, что я использую для уничтожения $:

    destroy$ = new Subject<void>();

    ngOnDestroy(): void {
      this.destroy$.next();
      this.destroy$.complete();
    }

«Если он пройдет, он зарегистрирует каждый ответ и зарегистрирует его в конце». Это не соответствует требованию 4

Fred2020 23.06.2024 10:43

@Fred2020 Fred2020 Просто удалите журнал внутри next. Тогда он не будет регистрировать каждый ответ и выполнит все ваши требования.

Markus 23.06.2024 16:38

Я не уверен, что соблюдаю требование 4: «Если оба успешны, я хочу зарегистрировать одно сообщение об успехе» ... поэтому я хочу, чтобы было зарегистрировано сообщение, одно для обоих успешных запусков, а не 1 для каждого успешного запуска.

Fred2020 23.06.2024 21:22

@Fred2020 Да. next логи для каждого запроса. error журналы каждого неудачного запроса. complete регистрирует, все ли запросы выполнены успешно. Поэтому, если вам нужен только один журнал, если оба успешны, удалите любой журнал внутри следующего. Тогда он будет регистрироваться только при ошибках или если оба пройдут без проблем.

Markus 24.06.2024 10:21

Другие вопросы по теме