「这是我参与2022首次更文挑战的第29天,活动详情查看:2022首次更文挑战」
对于一个完整的程序,对可预见的错误添加异常处理逻辑是必不可少的。在 Rxjs 中针对这个常见的需求也提供了一系列错误处理操作符,本节就来看一下这部分内容。
catchError
catchError 就是普通的 catch 的语义(叫 catchError 是为了避免和关键字重复),它的效果就是捕获 Observable 中抛出的错误,举个例子:
of(0, 1, 2, 3).pipe(
map(n => {
if (n === 2) {
throw new Error('error');
}
return n;
}),
catchError(err => of('catchError')),
).subscribe(x => console.log(x));
// 0
// 1
// catchError
可以看到当有错误抛出时,程序会流转到 catchError 中,catchError 可以用一个新的 Observable 作为返回值,此时订阅者可以收到新的 Observable 发出的数据。
使用弹珠图描述:
程序中的错误有很多种,在不同的情况下我们需要根据场景做对应处理,一个很常见的需求就是发生错误时执行重试逻辑。catchError 还有第二个参数,我们可以利用这个参数实现重试的效果:
of(0, 1, 2, 3).pipe(
map(n => {
if (n === 2) {
throw new Error('error');
}
return n;
}),
catchError((err, caught) => caught),
).subscribe(x => console.log(x));
// 0
// 1
// 0
// 1
// ...
catchError 直接返回第二个参数,当发生错误时就会重复原始的 Observable。不过在实际开发中想要实现错误重试不需要这么麻烦,retry 操作符是用来专门处理这个场景的。
retry
retry 操作符可以在出现错误时进行重试,可以接收一个重试次数作为参数,默认为无限次数,借助 retry 我们可以很容易地实现前一个例子的效果:
of(0, 1, 2, 3).pipe(
map(n => {
if (n === 2) {
throw new Error('error');
}
return n;
}),
retry(),
).subscribe(x => console.log(x));
// 0
// 1
// 0
// 1
// ...
可以使用弹珠图描述 retry 的过程(retry 用于存在错误时的重试,正常结束的流重试逻辑需要使用 repeat 操作符):
retryWhen
在实际开发中,有的时候需要的不一定是出现错误就重试,往往是需要伴随着一系列的条件,这里 Rxjs 提供了另一个和重试相关的操作符 retryWhen,在 retryWhen 中我们可以进一步处理重试相关逻辑。retryWhen 的用法不太容易描述,可以看一个例子来理解:
of(1, 2, 3, 4).pipe(
map((val) => {
if (val > 2) {
throw val;
}
return val;
}),
retryWhen((errors) =>
errors.pipe(
delay(2000)
)
)
).subscribe(x => console.log(x));
可以看到 retryWhen 中可以拿到 errors 对象,我们在 errors 可以读取到发生错误时的原始 Observable 信息,之后根据具体情况进行处理,这里的处理是延迟 2 秒,这样的效果就是先打印 1、2,之后发生错误进入 retryWhen 逻辑,等待两秒 retryWhen 中的 Observable 触发时再执行重试,接着打印出 1、2,不断重复。
弹珠图描述:
在 Rxjs 中,和错误处理相关的操作符主要就是这么多,虽然异常处理不在主程序流程中,但是实际开发中还是必不可少的。