Dart与Flutter中Future抛异常时主线程行为差异原因
问题描述
测试Future运行行为时观测到明显环境差异:纯Dart环境中Future抛出未捕获异常会中断主线程运行,但Flutter环境中不会出现该情况。
测试代码
Future(() async { await Future.delayed(Duration(seconds: 10)); print("TimeOut"); }).timeout(Duration(seconds: 5)); Future(() async { await Future.delayed(Duration(seconds: 15)); print("AAAAAAA"); });
不同环境运行结果
- 纯Dart环境:执行
dart run ./a.dart命令运行上述代码,5秒超时后直接抛出未处理异常,程序终止,后续的TimeOut、AAAAAAA打印均不会执行,输出内容为:
Unhandled exception: TimeoutException after 0:00:05.000000: Future not completed
- Flutter环境:运行相同代码时,虽会打印未捕获的TimeoutException错误日志,但后续
TimeOut、AAAAAAA均正常打印,日志输出如下:
E/flutter (11789): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: TimeoutException after 0:00:05.000000: Future not completed E/flutter (11789): I/flutter (11789): TimeOut I/flutter (11789): AAAAAAA
差异根本原因
两者行为不一致的核心是运行时对未捕获异步异常的默认处理策略不同:
- 纯Dart命令行程序运行在默认的根Zone中,未捕获的异步异常会触发Isolate的默认错误处理逻辑:打印异常信息后直接终止当前Isolate的事件循环,所有队列中等待执行的异步任务都会被直接丢弃,不会再运行。因此超时抛出异常后程序直接退出,后续的打印逻辑不会执行。
- Flutter框架启动时会在自定义的Zone中运行所有业务代码,重写了Zone的未捕获异常处理回调:默认行为仅将异常和堆栈信息打印到开发日志,不会终止Isolate的事件循环,事件循环会持续从任务队列中取出剩余任务执行。因此超时异常抛出后,两个延迟任务到期后仍会正常触发、打印对应内容。
额外说明:Future.timeout()方法本身不会取消内部原Future的执行,它只会在超时时限到达、原Future未完成时,给timeout方法返回的Future对象抛出超时异常,原Future内部的逻辑会继续运行直到完成,这也是Flutter环境下10秒到期后仍能打印出TimeOut的前提。
内容的提问来源于stack exchange,提问作者autop
相关产品推荐
相关产品推荐

