Dart中Future.delayed抛错被Timer回调捕获的不稳定问题
为什么Dart中Timer延迟1ms注册Future错误回调有时失败?
先看你提供的代码:
var future = Future<int>.delayed( const Duration(milliseconds: 220), () => throw Exception("Hello!")); Timer(const Duration(milliseconds: 219), () => future.then(print, onError: (err) => print(err)));
核心原因:事件循环调度与未处理异步错误规则
这不是Dart时间计算不精准的问题,而是由操作系统定时器精度和Dart的事件循环+未处理错误机制共同导致的:
任务的调度逻辑
Future.delayed和Timer都会将任务添加到Dart的事件队列中,等待指定延迟后执行。但操作系统的定时器本身存在精度限制(多数系统的定时器精度在1~10ms之间),加上单线程事件循环一次只能处理一个任务,当两个任务的延迟时间差极小时(比如1ms),谁先进入事件队列并执行是不确定的。
两种执行场景
- 场景1:Timer回调先执行
Timer的回调先触发,此时future还处于未完成状态。调用future.then(...)相当于提前给这个Future注册了错误回调,等后续Future执行抛出错误时,回调会被正常触发,因此能捕获到错误。 - 场景2:Future任务先执行
Future的任务先触发并抛出错误,此时还没有任何错误回调被注册。Dart会将这个错误标记为未处理异步错误,并在当前事件处理完成后检查未处理错误列表,输出错误信息。之后Timer回调执行时再注册onError回调,此时错误已经被标记为未处理,不会再触发回调,因此你看不到预期的错误输出。
- 场景1:Timer回调先执行
增大延迟差为什么有效?
当把Timer的延迟改为100ms时,Timer回调的触发时间远早于Future的任务,能确保在Future抛出错误前就完成回调注册,因此每次都能捕获到错误。
正确的错误捕获方式
如果要确保Future的错误被捕获,建议在创建Future时直接注册回调,或者使用async/await语法,避免依赖Timer的延迟调度:
方式1:直接链式调用
var future = Future<int>.delayed( const Duration(milliseconds: 220), () => throw Exception("Hello!") ).then(print, onError: (err) => print(err));
方式2:使用async/await
void main() async { try { await Future<int>.delayed( const Duration(milliseconds: 220), () => throw Exception("Hello!") ); } catch (err) { print(err); } }
内容的提问来源于stack exchange,提问作者Anonymous
相关产品推荐
相关产品推荐

