RxJS 系列 – Error Handling Operators

前言

前几篇介绍过了 

Creation Operators

Filter Operators

Join Creation Operators

这篇继续介绍 Error Handling Operators.

 

参考

RxJS 錯誤處理 Operators (1) - catchError / finalize / retry / retryWhen

Docs – Error Handling Operators

 

Observable and Subscriber Handler Error

Observable 的流程是 : Observable init > pipe > subscribe

不经过 pipe 的情况下, 处理 error 的方式如下:

const obs = new Observable(subscriber => {
  subscriber.error('error message');
  // throw 'error message'; // throw 也是可以
});
obs.subscribe({
  error: errorMessage => console.log(errorMessage), // error message
});

简单明了.

 

catchError

catchError 是 pipe 阶段的 error handle. 它是 operator 来的.

catch error and change to succeeded

const obs = new Observable(subscriber => {
  subscriber.error('error message');
});
obs
  .pipe(
    catchError(error => {
      console.log(error); // error message
      return of('succeeded');
    })
  )
  .subscribe({
    next: value => console.log(value), // succeeded
    error: errorMessage => console.log(errorMessage), // won't call
  });

catchError 接收到 error 后, 可以有几个处理方式. 上面这个是返回一个 "成功" 的 Observable, 这样 error 就不会在传下去了. 

catch error and re-throw

catch error 然后继续往下 throw error,

throwError 方法之前介绍过了, 它是 Creation Operators 的一员.

catchError(error => {
  return throwError(() => 're-throw error');
  // throw 're-throw error'; // 用 throw 也可以
})

小结

总之, catchError 要返回一个 Observable, 可以是 succeeded 或者是 error

catchError(error => {
  if (Math.random() < 0.5) {
    return throwError(() => 're-throw error');
    // throw 're-throw error'; // 用 throw 也可以
  } else {
    return of('succeeded');
  }
})

catch error and retry

除了 succeeded 和 error, 还有一种处理方式是 retry. 所谓 retry 就是 unsubscribe 当前的 stream, 重新 subscribe Observable 得到新的 stream (旧的 Observable 会 displose, 新的会 init)

catchError((error, caught) => {
    return caught;
})

返回 catchError 的第二个参数 caught 就表示要 retry. retry 可能会导致死循环的哦.

所以必须要有条件, 避开死循环, 比如:

catchError((error, caught) => {
  if (Math.random() < 0.5) {
    return caught; // retry
  } else {
    return of('succeeded');
  }
})

delay retry

catchError((error, caught) => {
  return timer(2000).pipe(switchMap(() => caught));
})

返回一个 delay 的 Observable 就可以延后 retry 了. 这里用了 switchMap 把 timer 的值换成了 caught observable. (这个 operator 我还没有介绍过的)

retry count

要计算 count 只能开一个外部的 variable 做记入. 或者封装一个自定义 operator. 但更简单的方法是直接用 RxJS 提供的 retry 和 retryWhen operator. 下面会介绍.

 

retry

用 catchError + caught 实现 retry 太费劲了, 所以 RxJS 封装了 retry operator

retry({
  count: 3,
  delay: 2000,
  resetOnSuccess: false,
})

count 声明可以 retry 多少次

delay 声明 retry 的间隔时间, 有时候 error 是因为 server 繁忙, 只要等 1,2 秒在 retry 发 ajax 就可以解决了.

此外 delay 还支持更复杂的 config. 通过判断 error 和 retryCount 来决定要 delay 多少秒.

我们甚至可以返回 click$ 让 user 点击触发 retry. 

也可以直接返回 throwError 结束 retry (即便还没有 hit 到 max retry count), 灵活就对了

delay: (error, retryCount) => timer(2000 * retryCount)

resetOnSuccess 用来表达当 retry 成功以后是否要 reset retry count,默认值是 false,通常 reset 是正确的,所以一般我都是 set 成 true。

有一个场景需要 false,那就是 Angular HttpClient.request upload file 的时候。

httpClient.request upload 的 event dispatch 是这样:

event for upload percentage 10% > 40% > 80% > 100% > response error > retry 1 > 10% 注意这里是 success,不是 error  > 40% > 80% > 100% > response error > return 1

为什么不是 retry 2?因为 10% 是 success,然后 resetOnSuccess: true,所以第二次 response error 时,retry count 已经 reset 回到 1 了。

这种情况 resetOnSuccess 就不太合适。

 

retryWhen

已经废弃了, 改用 retry + delay option 实现吧.

 

 

一句话总结

catchError : 在 pipe 中 catch error, 3中处理, 成功, 继续 error, retry

retry : 用 catchError 做 retry 太费劲就有了 retry operator

retryWhen : 废弃了, 改用 retry + delay option 实现.

 

posted @ 2022-10-02 14:39  兴杰  阅读(232)  评论(0编辑  收藏  举报