如何获取多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
相关产品推荐
相关产品推荐

