订阅仅在发生错误后触发一次

时间:2020-05-26 19:52:23

标签: rxjs

我是rxjs的新手,我想弄清楚以下代码中发生了什么。

实际上,为了说明这个想法,我准备了两个简单的Promise(resolvePromise和rejectPromise),一个解决了一个Promise,另一个拒绝了。 “主题”实例用于触发这两个承诺(通过mergeMap和forkJoin用管道传输)。最后,添加了两个单独的指令(source $ .next('xxx')),希望触发两次订阅。

但是最后,只有第一个“ source $ .next('1')”会触发订阅,而下一个“ source $ .next('2')”似乎什么也没做。

我猜这是由拒绝承诺引起的,它实际上是“引发异常”。 但是我想知道如何解决此代码,以便第二个“ source $ .next('2')”也将触发订阅。

非常感谢

import { of,forkJoin,Subject } from 'rxjs';
import { mergeMap } from 'rxjs/operators';

const resolvePromise = val =>
  new Promise(resolve => resolve(`resolve value: ${val}`));

const rejectPromise = err =>
  Promise.reject(`reject error: ${err}`);

const source$ = new Subject();

source$
  .pipe(mergeMap(val => {
    return forkJoin([
      resolvePromise(val), 
      rejectPromise(val)
      ]);
  }))
  .subscribe(
     console.log, 
     console.error
  );

  source$.next('1');
  source$.next('2');

更新

基于下面的AndreiGătej的建议,为了克服此问题,我选择在forkJoin之后传递一个catchError,并将错误处理放入其中。

source$.pipe(
  mergeMap(val => {
    return forkJoin([
      resolvePromise(val),
      rejectPromise(val)
    ])
      .pipe(
        catchError(err => {
          // your error handling business logic
          console.error(err);
          return empty();
        })
      );
  }))
  .subscribe(console.log);

2 个答案:

答案 0 :(得分:1)

拒绝承诺,实际上是“引发异常”

从RxJS内部处理诺言的角度来看,我说您是对的:

promise.then(
  (value) => {
    if (!subscriber.closed) {
      subscriber.next(value);
      subscriber.complete();
    }
  },
  (err: any) => subscriber.error(err) // !
)

Source

还有一点值得一提的是,正如您从上面的代码段中看到的那样,当承诺第一次解决时,已解决的值和一个complete通知就会过去了。

complete部分对于forkJoin运算符非常重要。

forkJoin订阅所有提供的可观察对象,并等待,直到全部完成。仅当可观察对象至少发射一次 时,才会发送具有值的数组。

当一个可观察对象发出error通知时,forkJoin将立即在链中进一步发送该error通知。


这是我的方法:

ource$
  .pipe(mergeMap(val => {
    return forkJoin([
      resolvePromise(val), 
      from(rejectPromise(val)).pipe(catchError(err => of(err)))
      ]);
  }))
  .subscribe(
     console.log, 
     console.error
  );

我们正在使用from,以便我们可以拦截尽早承诺错误,这使我们可以使用catchError并使用可观察值,它将发送一个值,然后complete通知(of(err))。

答案 1 :(得分:0)

您需要通过retryrepeat重新订阅。

import { of,forkJoin,Subject } from 'rxjs';
import { mergeMap } from 'rxjs/operators';

const resolvePromise = val =>
  new Promise(resolve => resolve(`resolve value: ${val}`));

const rejectPromise = err =>
  Promise.reject(`reject error: ${err}`);

const source$ = new Subject();

source$.pipe(
  mergeMap(val => forkJoin([
    resolvePromise(val), 
    rejectPromise(val)
  ])),
  catchError(() => EMPTY),
  repeat(),
).subscribe(
  console.log, 
  console.error
);

source$.next('1');
source$.next('2');