Skip to content

AHABHGK

异常错误处理

异常处理的难点

虽然必要,但会让代码更加复杂

try / catch 只支持同步,因为 try / catch 是同步执行,执行后里面的异步代码还没有执行,就抓不到异步代码的错误

因此出现 callback,通过传递 cb 参数把异步之后的逻辑传入,相应错误处理也放到异步代码内部,但是有 cbhell 问题

之后出现 Promise,虽然也是传入 cb 处理,但是将 cb 嵌套结构展平成链式结构,解决代码结构问题,但是设计上由于 Promise 最终转换为 fulfilled 或 rejected 态就结束了,重试的逻辑不能由 promise 本身处理

Promise 和 Observable 同属 Monod,Promise 中的 then 相当于 map

RxJS 的异常处理

在函数式编程中,throw new Error() 相当于增加了函数一个新的出口,抛出去的异常可能会导致副作用,导致函数不纯

同时从 caller 的角度,不仅需要处理返回值,还有处理可能的异常,这更加重了 caller 的负担

在 $ 中,异常只会在自己的管道中处理掉,或是流到下游通过 theObserver.error 处理,不会影响其他的流或是全局的状态

管道中的处理分为恢复重试

  • 恢复:虽然产生了错误,但是依然让运算进行下去,比如通过 defaultValue

  • 重试:要有上限,最终不行还是要用恢复

catchError 恢复

selector: a function that takes as arguments err, which is the error, and caught, which is the source observable, in case you'd like to "retry" that observable by returning it again. Whatever observable is returned by the selector will be used to continue the observable chain

用作重试:

1of(1, 2, 3, 4, 5).pipe(
2 map(n => {
3 if (n === 4) {
4 throw 'four!'
5 }
6 return n
7 }),
8 catchError((err, caught$) => caught$),
9 take(10),
10).subscribe(x => console.log(x))
11// 1, 2, 3, 1, 2, 3, 1, 2, 3, 1

给 theObserver.error 处理:

1of(1, 2, 3, 4, 5).pipe(
2 map(n => {
3 if (n === 4) {
4 throw 'four!'
5 }
6 return n
7 }),
8 catchError((err, caught$) => {
9 throw err
10 }),
11).subscribe(console.log, console.error)

retry 重试

retry<T>(count: number = -1): MonoTypeOperatorFunction<T>

retry 是立即执行重试的,有时需要等到某个时机再重试:retryWhen

Returns an Observable that mirrors the source Observable with the exception of an error. If the source Observable calls error, this method will emit the Throwable that caused the error to the Observable returned from notifier. If that Observable calls complete or error then this method will call complete or error on the child subscription. Otherwise this method will resubscribe to the source Observable.

1error$.pipe(
2 ((max) => retryWhen(err$ => err$.pipe(
3 scan((errorCount, error) => {
4 if (errorCount >= max) throw error
5 return errorCount + 1
6 })
7 )))(3),
8) // retry(3)

同样可以抽象出延迟并有上限的重试等其他操作符

finalize

Callback will call a specified function when the source terminates on complete or error.

重试的本质

重新订阅,先退订然后再订阅