侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

实现一个带错误处理和超时控制的异步数据流处理器

2025-12-11 / 0 评论 / 4 阅读

题目

实现一个带错误处理和超时控制的异步数据流处理器

信息

  • 类型:问答
  • 难度:⭐⭐

考点

Future链式调用,Stream处理,错误处理,超时控制

快速回答

实现一个异步处理器,要求:

  1. 从两个异步数据源获取数据(模拟API)
  2. 合并数据后转换格式
  3. 添加超时控制(2秒)
  4. 实现错误处理机制

核心代码要点:

  • 使用Future.wait并行获取数据
  • async/await处理异步流程
  • 通过timeout设置超时
  • 使用try-catch捕获异常
  • Stream.fromIterable输出结果
## 解析

问题场景

需要从两个异步数据源获取用户数据和订单数据,合并后转换为指定格式,要求:

  1. 并行获取数据提高效率
  2. 整个流程超时时间为2秒
  3. 优雅处理可能出现的错误
  4. 结果通过Stream输出

解决方案

Stream<Map<String, dynamic>> processUserData() async* {
  try {
    // 并行获取数据
    final results = await Future.wait([
      _fetchUserData(),
      _fetchOrderData()
    ], eagerError: true).timeout(
      const Duration(seconds: 2),
      onTimeout: () => throw TimeoutException('Processing timed out')
    );

    // 数据转换
    final user = results[0] as Map<String, dynamic>;
    final orders = results[1] as List<dynamic>;

    // 格式转换并输出
    yield {
      'userId': user['id'],
      'userName': user['name'],
      'orderCount': orders.length,
      'lastOrder': orders.isNotEmpty ? orders.last : null
    };
  } 
  catch (e) {
    // 统一错误处理
    yield {'error': e.toString()};
  }
}

// 模拟API请求
Future<Map<String, dynamic>> _fetchUserData() async {
  await Future.delayed(Duration(milliseconds: 1500));
  return {'id': 'U123', 'name': 'John Doe'};
}

Future<List<dynamic>> _fetchOrderData() async {
  await Future.delayed(Duration(milliseconds: 800));
  return [
    {'id': 'O789', 'total': 49.99},
    {'id': 'O002', 'total': 149.99}
  ];
}

核心原理

  • Future.wait:并行执行多个Future,eagerError=true确保立即抛出首个错误
  • timeout:限制整个异步操作的执行时间,超时抛出TimeoutException
  • async* 和 yield:创建异步数据流,逐步输出结果
  • 统一错误处理:catch块捕获所有异常(包括超时和API错误)并转换为数据格式

最佳实践

  1. 优先使用async/await代替回调嵌套,提高可读性
  2. 为并行操作设置eagerError:true避免不必要的等待
  3. 超时时间应略大于正常请求耗时(示例中总耗时1.5秒,超时2秒)
  4. 错误信息转换为结构化数据,保持输出流一致性

常见错误

错误示例问题分析修正方案
await _fetchUserData(); await _fetchOrderData();顺序执行降低效率改用Future.wait并行
缺少timeout可能永久阻塞始终为网络请求添加超时
未处理onTimeout超时返回null导致后续崩溃明确抛出异常

扩展知识

  • StreamController:更复杂的流控制场景可使用StreamController手动添加事件
  • 错误隔离:使用Future.catchError为单个Future添加专属错误处理
  • 重试机制:通过retry包或递归实现自动重试
  • 测试技巧:使用FakeAsync模拟时间流逝,验证超时逻辑