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

