You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取多API请求场景下Stream及Futures的执行进度?

实现多Future Stream的进度追踪

静态分配进度

如果你的5个API请求耗时差异不大,静态分配是最直接的方案——给每个任务预先设定权重百分比,完成一个就累加对应进度。比如你提到的前两个任务各占20%(合计40%),剩下三个各占20%,实现起来非常简单:

// 模拟5个API请求Future
Future<void> apiCall1() async => await Future.delayed(const Duration(seconds: 2));
Future<void> apiCall2() async => await Future.delayed(const Duration(seconds: 2));
Future<void> apiCall3() async => await Future.delayed(const Duration(seconds: 2));
Future<void> apiCall4() async => await Future.delayed(const Duration(seconds: 2));
Future<void> apiCall5() async => await Future.delayed(const Duration(seconds: 2));

Stream<int> trackStaticProgress() async* {
  int currentProgress = 0;
  // 给每个任务分配固定权重百分比
  const taskWeights = [20, 20, 20, 20, 20];
  final tasks = [apiCall1, apiCall2, apiCall3, apiCall4, apiCall5];

  for (int i = 0; i < tasks.length; i++) {
    await tasks[i]();
    currentProgress += taskWeights[i];
    yield currentProgress;
  }
}

// 调用示例
void main() async {
  await for (final progress in trackStaticProgress()) {
    print("完成进度:$progress%");
  }
}

动态获取进度

如果各个API请求耗时差异很大,静态分配会导致进度条跳变不真实,这时候可以通过实时监听任务完成状态来动态计算进度。如果是普通API请求(无字节级进度),可以用「已完成任务数/总任务数」的比例更新;如果API支持返回字节进度(比如下载类接口),还可以把单个任务的内部进度整合到总进度里,实现更精细的追踪:

基础动态进度(基于任务完成数)

Stream<double> trackDynamicProgress() async* {
  const totalTasks = 5;
  final controller = StreamController<double>();
  int completedTasks = 0;

  // 同时启动所有任务,完成一个就推送最新进度
  final futures = [
    apiCall1().then((_) {
      completedTasks++;
      controller.add((completedTasks / totalTasks) * 100);
    }),
    apiCall2().then((_) {
      completedTasks++;
      controller.add((completedTasks / totalTasks) * 100);
    }),
    apiCall3().then((_) {
      completedTasks++;
      controller.add((completedTasks / totalTasks) * 100);
    }),
    apiCall4().then((_) {
      completedTasks++;
      controller.add((completedTasks / totalTasks) * 100);
    }),
    apiCall5().then((_) {
      completedTasks++;
      controller.add((completedTasks / totalTasks) * 100);
      controller.close();
    }),
  ];

  await Future.wait(futures);
  yield* controller.stream;
}

进阶动态进度(整合单个任务内部进度)

如果某个API支持返回字节级进度(比如下载文件),可以给该任务分配更高权重,再把它的内部进度映射到总进度区间:

// 模拟带进度回调的API
Future<void> apiWithProgress(Function(double) onProgress) async {
  for (int i = 0; i <= 100; i += 10) {
    await Future.delayed(const Duration(milliseconds: 500));
    onProgress(i / 100);
  }
}

Stream<double> trackAdvancedProgress() async* {
  final controller = StreamController<double>();
  double totalProgress = 0;
  // 任务权重:前两个占40%(各20%),第三个占30%,后两个各15%
  const taskWeights = [20, 20, 30, 15, 15];

  // 处理带内部进度的任务
  final task3 = apiWithProgress((innerProgress) {
    // 计算该任务贡献的进度:权重 * 内部完成比例
    final taskContribution = taskWeights[2] * innerProgress;
    // 总进度 = 已完成任务的权重和 + 当前任务的贡献
    final completedWeight = taskWeights.sublist(0, 2).reduce((a, b) => a + b);
    totalProgress = completedWeight + taskContribution;
    controller.add(totalProgress);
  });

  // 先完成前两个无进度的任务
  await apiCall1();
  totalProgress += taskWeights[0];
  controller.add(totalProgress);

  await apiCall2();
  totalProgress += taskWeights[1];
  controller.add(totalProgress);

  // 等待带进度的任务完成
  await task3;

  // 完成剩下的任务
  await apiCall4();
  totalProgress += taskWeights[3];
  controller.add(totalProgress);

  await apiCall5();
  totalProgress += taskWeights[4];
  controller.add(totalProgress);

  controller.close();
  yield* controller.stream;
}

方案选择

  • 静态分配:适合任务耗时均匀的场景,实现成本低,进度展示稳定。
  • 动态分配:适合任务耗时差异大的场景,进度更贴合实际执行情况,进阶版还能支持精细的任务内部进度追踪。

内容的提问来源于stack exchange,提问作者Daniel Roldán

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 06:33:35