Dart多异步抛出引发未处理异常,如何捕获全部异常?
如何捕获所有异步调用抛出的异常?
你的推测完全正确。当await future1抛出异常时,asyncMethod会立即终止执行,不会走到await future2这一步。但future2在之前已经被创建并启动,它抛出的异常没有任何代码去监听处理,因此会成为未处理异步异常,导致程序后续报错。
以下是几种确保捕获所有异步异常的解决方案:
方案1:使用Future.wait统一处理并行Future的异常
Future.wait可以同时等待多个并行执行的Future,通过不同的写法可以实现不同的异常处理逻辑:
方式A:捕获首个异常(默认行为)
Future.wait默认会在第一个Future失败时立即抛出异常,适合只需要知道是否有失败的场景:
import 'dart:async'; Future<bool> asyncFuncThatThrows(Duration duration, String message) { return Future.delayed( duration, () => throw Exception('$message asyncFuncThatThrows')); } Future<void> asyncMethod() async { print('asyncMethod start'); final futures = [ asyncFuncThatThrows(Duration(seconds: 0), 'first '), asyncFuncThatThrows(Duration(seconds: 0), 'second '), ]; print('asyncMethod -> functions that throw executed'); try { await Future.wait(futures); } catch (e) { print('Caught error in asyncMethod: $e'); } print('asyncMethod done'); } void main() async { try { print('Start'); await asyncMethod(); } catch (e) { print('Try/Catch in main: $e'); } print('Done'); }
方式B:捕获所有异常
如果需要收集并处理所有Future的异常,给每个Future单独添加catchError处理,确保没有未处理异常:
Future<void> asyncMethod() async { print('asyncMethod start'); final futures = [ asyncFuncThatThrows(Duration(seconds: 0), 'first ') .catchError((e) => print('Handled first error: $e')), asyncFuncThatThrows(Duration(seconds: 0), 'second ') .catchError((e) => print('Handled second error: $e')), ]; print('asyncMethod -> functions that throw executed'); await Future.wait(futures); print('asyncMethod done'); }
这种方式下所有Future的异常都会被单独处理,不会出现未处理异常,asyncMethod也能正常执行到结束。
方案2:串行await并逐个处理异常
如果不需要并行执行Future,可以逐个await并给每个异步调用单独添加try-catch,前一个失败不会影响后一个的执行:
Future<void> asyncMethod() async { print('asyncMethod start'); print('asyncMethod -> functions that throw executed'); try { await asyncFuncThatThrows(Duration(seconds: 0), 'first '); } catch (e) { print('Caught first error: $e'); } try { await asyncFuncThatThrows(Duration(seconds: 0), 'second '); } catch (e) { print('Caught second error: $e'); } print('asyncMethod done'); }
方案3:用带错误回调的runZoned捕获全局未处理异常
你之前使用的runZoned没有生效,是因为缺少onError回调。配置该回调后,可以捕获Zone内所有未处理的异步异常:
void main() { runZoned(() async { try { print('Start'); await asyncMethod(); } catch (e) { print('Try/Catch in main: $e'); } print('Done'); }, onError: (e, stackTrace) { print('Caught by runZoned: $e'); print('Stack trace: $stackTrace'); }); }
关于DartPad无未处理异常的疑问
DartPad的运行环境默认配置了全局异常捕获机制,会自动处理未处理的异步异常并隐藏报错输出;而本地Dart运行时没有这个默认处理,因此会显示完整的未处理异常栈信息。
内容的提问来源于stack exchange,提问作者Alvaro Mateo
相关产品推荐
相关产品推荐

