Как не запускать обработчик ‘complete’ при возникновении ошибки в concatMap?

#rxjs #rxjs-observables

#rxjs #rxjs-наблюдаемые

Вопрос:

При работе с concatMap, как я могу прервать выполнение наблюдаемых дальше по строке и предотвратить вызов обработчика завершения?
Вот простой пример.

 of(...[1, 2, 3]).pipe(
  concatMap(t => of(t)),
  map(n => {
    console.log(n);
    if (n === 2) {
      throw new Error('OK, fail here');
    }
  }),
  catchError((e, c) => of(console.log('Caught '   e)))
)
  .subscribe(
    {
      complete: () => console.log('Complete should not be triggered in an error case, but here it is'),
      error: (err: any) => {
        console.log('I did never trigger, thats ok!');
      }
    });
 

Наблюдаемый источник выдает 1,2,3, который передается в concatMap.
Возможны два сценария: все три наблюдаемых генерируются без ошибок, в этом случае должен быть запущен полный обработчик. Или другой случай, изображенный здесь: где-то в конце строки возникает ошибка, например, когда n === 2. concatMap прекращает выполнение следующего наблюдаемого, что идеально, но все равно запускает обработчик завершения, что нежелательно.

Фактический результат

1
2
Обнаруженная ошибка: ОК, сбой здесь
Завершение не должно запускаться в случае ошибки, но вот оно

Желаемый результат

1
2
Обнаруженная ошибка: ОК, сбой здесь

Какие-либо подсказки? Моей предыдущей попыткой было запустить следующий обработчик, но это оказалось действительно плохо:/ поскольку это вызвало hostReportError

Ответ №1:

Хорошо, поскольку я смог самостоятельно ответить на все другие интересные вопросы, касающиеся RxJS, поехали 🙂

Помните: catchError заменяет ошибочный наблюдаемый объект каким-либо другим наблюдаемым объектом. catchError Поэтому, если бы возвращался наблюдаемый через throwError , это остановило бы выполнение и, что еще лучше, это вызвало бы обработчик ошибок, который раньше был простаивающим.

     of(...[1, 2, 3]).pipe(
      concatMap(t => of(t)),
      map(n => {
        console.log(n);
        if (n === 2) {
          throw new Error('OK, fail here');
        }
      }),
      catchError((e, c) => throwError(e)) // This line has changed
    )
      .subscribe(
        {
          complete: () => console.log('Complete should not be triggered in an error case, but here it is'),
          error: (err: any) => {
            console.log('Now I have something to do, yay!');
          }
        });

 

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

1. Здесь вам вообще не нужен catchError оператор. Каждый оператор эффективно окружен блоком try-catch и превращает поток в поток с ошибкой, если генерируется исключение. throw new Error('OK, fail here'); уже вызовет ваш error обратный вызов в вашей подписке. Который, если подумать, должен работать, поскольку это тот же обратный catchError вызов, к которому подключается оператор.