React编程高级主题:错误处理(Error Handling)

发布于:2025-04-05 ⋅ 阅读:(17) ⋅ 点赞:(0)

在这里插入图片描述

在这里插入图片描述

5.2 错误处理(Error Handling)概述

React + RxJS/Reactive Programming 生态中,数据流(Stream)可能会因 网络错误、API 异常、数据处理失败 等原因抛出错误。如果未正确处理,错误可能导致整个数据流终止,影响用户体验。

错误处理的核心目标

  1. 防止错误导致整个应用崩溃(Graceful Degradation)。
  2. 提供合理的错误恢复机制(Retry/Fallback)。
  3. 记录错误信息(Logging & Monitoring)。

React 生态中常见的错误处理方式包括:

  • onErrorReturn / onErrorResume(错误回退)
  • retry / retryWhen(错误重试)

接下来,我们将深入探讨这些方法的 原理、实现方式及适用场景


在这里插入图片描述

5.2.1 onErrorReturn / onErrorResume(错误回退)

1. onErrorReturn:提供默认值

核心思想:当数据流发生错误时,返回一个 默认值 替代错误,使流继续执行。

适用场景

  • 适用于 可预测的错误(如 API 404 返回默认数据)。
  • 不希望错误中断数据流,但可以接受降级数据。

示例(RxJS)

import { of, throwError } from 'rxjs';
import { onErrorReturn } from 'rxjs/operators';

const source$ = throwError(new Error('API Failed')); // 模拟错误

source$
  .pipe(
    onErrorReturn(() => ({ data: 'Default Value' })) // 错误时返回默认值
  )
  .subscribe({
    next: (val) => console.log('Received:', val), // 输出: Received: { data: 'Default Value' }
    error: (err) => console.error('Error:', err), // 不会触发
  });

底层原理

  • onErrorReturn 会在 error 发生时拦截错误,并调用回调函数返回一个默认值。
  • 该操作符会 终止原 Observable,并返回一个新的 Observable,发射默认值后 complete

在这里插入图片描述

2. onErrorResume:切换备用数据流

核心思想:当主数据流失败时,切换到备用数据流(Fallback Stream)。

适用场景

  • 主 API 失败时,回退到缓存/备用 API。
  • 多数据源冗余设计(如 CDN 回源)。

示例(RxJS)

import { of, throwError } from 'rxjs';
import { onErrorResumeWith } from 'rxjs/operators';

const mainApi$ = throwError(new Error('Main API Down'));
const fallbackApi$ = of({ data: 'Fallback Data' });

mainApi$
  .pipe(
    onErrorResumeWith(fallbackApi$) // 主API失败时切换到备用流
  )
  .subscribe({
    next: (val) => console.log('Received:', val), // 输出: Received: { data: 'Fallback Data' }
    error: (err) => console.error('Error:', err), // 不会触发
  });

底层原理

  • onErrorResumeWith 会在错误发生时 取消订阅原 Observable,并立即订阅备用 Observable。
  • 如果备用流也失败,错误会继续传播(除非嵌套使用多个 onErrorResumeWith)。

在这里插入图片描述

5.2.2 retry / retryWhen(错误重试)

1. retry:固定次数重试

核心思想:在发生错误时,自动重新订阅数据流(可设定最大重试次数)。

适用场景

  • 临时性错误(如网络抖动、API 限流)。
  • 需要 简单重试逻辑 的场景。

示例(RxJS)

import { throwError, timer } from 'rxjs';
import { retry } from 'rxjs/operators';

let attempts = 0;
const flakyApi$ = new Observable((subscriber) => {
  attempts++;
  if (attempts < 3) {
    subscriber.error(new Error('API Failed')); // 前两次模拟失败
  } else {
    subscriber.next('Success on attempt ' + attempts);
    subscriber.complete();
  }
});

flakyApi$
  .pipe(
    retry(2) // 最多重试2次(共3次尝试)
  )
  .subscribe({
    next: (val) => console.log('Received:', val), // 输出: Received: Success on attempt 3
    error: (err) => console.error('Error:', err), // 如果第3次仍失败,会触发
  });

底层原理

  • retry(n) 会在每次错误时重新订阅源 Observable,最多 n 次。
  • 如果所有重试均失败,错误会传递给 Subscriber

在这里插入图片描述

2. retryWhen:高级条件重试

核心思想:通过 自定义逻辑控制重试策略(如指数退避、依赖条件重试)。

适用场景

  • 复杂重试策略(如指数退避、Token 刷新后重试)。
  • 需要 动态调整重试行为(如根据错误类型决定是否重试)。

示例(RxJS:指数退避)

import { throwError, timer } from 'rxjs';
import { retryWhen, mergeMap, delay } from 'rxjs/operators';

const flakyApi$ = throwError(new Error('API Failed'));

flakyApi$
  .pipe(
    retryWhen((errors) =>
      errors.pipe(
        mergeMap((err, attempt) => {
          if (attempt >= 3) {
            return throwError(err); // 超过3次后放弃
          }
          const delayMs = 1000 * 2 ** attempt; // 指数退避:1s, 2s, 4s...
          console.log(`Retry in ${delayMs}ms`);
          return timer(delayMs); // 延迟后重试
        })
      )
    )
  )
  .subscribe({
    next: (val) => console.log('Received:', val),
    error: (err) => console.error('Final Error:', err), // 输出: Final Error: Error: API Failed
  });

在这里插入图片描述
底层原理

  1. retryWhen 接收一个 Observable<Error>,允许自定义重试逻辑。
  2. 每次错误时,可以:
    • 返回 Observable 延迟重试(如 timer)。
    • 返回 throwError 终止重试。
  3. 适用于 Token 刷新后重试
    retryWhen((errors) =>
      errors.pipe(
        mergeMap((err) => {
          if (isTokenExpired(err)) {
            return refreshToken().pipe( // 先刷新Token
              mergeMap(() => timer(1000)) // 再延迟重试
            );
          }
          return throwError(err); // 非Token错误直接抛出
        })
      )
    )
    

在这里插入图片描述

5.3 错误处理策略对比

方法 适用场景 优点 缺点
onErrorReturn 提供默认值(如空数据、占位图) 简单易用,确保流不中断 无法恢复真实数据
onErrorResume 切换到备用数据源(如缓存/冗余API) 支持多数据源冗余 备用数据可能不一致
retry 临时性错误(如网络抖动) 自动重试,减少手动处理 可能加重服务器负载(无限重试时)
retryWhen 复杂重试逻辑(如指数退避、Token刷新) 灵活控制重试策略 实现复杂度较高

5.4 总结

错误回退(Fallback)

  • onErrorReturn:适合静态降级(如默认值)。
  • onErrorResume:适合动态降级(如备用API)。

错误重试(Retry)

  • retry(n):适合简单重试(固定次数)。
  • retryWhen:适合高级策略(指数退避、条件重试)。
    在这里插入图片描述

最佳实践

  1. 关键数据:优先使用 retryWhen + onErrorResume 保证可用性。
  2. 非关键数据:使用 onErrorReturn 快速降级。
  3. 监控所有错误:在 subscribeerror 回调中记录日志。

通过合理组合这些策略,可以构建 健壮、可恢复的 React 数据流应用


网站公告

今日签到

点亮在社区的每一天
去签到