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

如何在Dart的Zone中自动捕获所有创建的Future?

在Dart中自动捕获Zone内的所有Future

你需要自动捕获Zone内创建的所有Future,避免手动添加的遗漏,核心是拦截Zone底层的异步调度操作——所有Future的执行最终都依赖微任务或定时器调度,只要覆盖这两个场景就能实现自动捕获。

你之前的尝试失败,是因为仅拦截了run/runUnary/runBinary方法,这些方法仅在显式调用Zone.run系列方法时触发,直接调用外部脚本中的函数不会经过这些拦截器,因此无法捕获返回的Future。

解决方案

通过ZoneSpecification拦截scheduleMicrotask和createTimer方法,为每个异步任务创建跟踪用的Future并加入任务列表,覆盖所有异步调度场景:

import 'dart:async';

Future<void> main() async {
  print('Run plugin code');
  await runZoned(
    () async {
      runPluginCode();

      final tasks = Zone.current['tasks'] as List<Future>;
      await Future.wait(tasks);
    },
    zoneValues: {
      'taskId': 123,
      'tasks': <Future>[],
    },
    zoneSpecification: ZoneSpecification(
      // 拦截微任务调度
      scheduleMicrotask: (self, parent, zone, microtask) {
        final completer = Completer<void>();
        void wrappedMicrotask() {
          try {
            microtask();
            completer.complete();
          } catch (e, stackTrace) {
            completer.completeError(e, stackTrace);
          }
        }
        parent.scheduleMicrotask(zone, wrappedMicrotask);
        (zone['tasks'] as List<Future>).add(completer.future);
      },
      // 拦截一次性定时器创建
      createTimer: (self, parent, zone, duration, callback) {
        final completer = Completer<void>();
        void wrappedCallback() {
          try {
            callback();
            completer.complete();
          } catch (e, stackTrace) {
            completer.completeError(e, stackTrace);
          }
        }
        final timer = parent.createTimer(zone, duration, wrappedCallback);
        (zone['tasks'] as List<Future>).add(completer.future);
        return timer;
      },
      // 如需处理周期性定时器,可添加createPeriodicTimer拦截
      // createPeriodicTimer: (self, parent, zone, duration, callback) {
      //   // 周期性定时器需根据业务决定跟踪方式,比如跟踪到取消为止
      //   return parent.createPeriodicTimer(zone, duration, callback);
      // },
    ),
    // 可选:添加错误处理,避免未捕获异常导致程序崩溃
    onError: (error, stackTrace) {
      print('Zone error: $error\n$stackTrace');
    },
  );
  print('Exit plugin code');
}

void runPluginCode() {
  someTask();
}

void someTask() {
  print('performing task');
  someAsyncWork();
}

Future<void> someAsyncWork() async {
  await Future.delayed(const Duration(milliseconds: 200));
  final taskId = Zone.current['taskId'] as int;
  print('async work completed for task $taskId did I complete inside the plugin code???');
}

效果说明

运行这段代码后,Exit plugin code会在所有异步任务完成后打印,Zone内的所有异步操作(包括someAsyncWork中的延迟任务)都会被自动捕获并等待完成,无需手动添加Future到任务列表。

内容的提问来源于stack exchange,提问作者Matthiee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 23:48:11