题目
Dart异步编程:Future与async/await的异常处理
信息
- 类型:问答
- 难度:⭐⭐
考点
异步编程,异常处理,Future,async/await
快速回答
在Dart异步编程中处理异常的关键点:
- 使用
try/catch包裹await调用捕获同步和异步异常 - 通过
.catchError()处理Future链式调用中的异常 - 避免在
async函数中遗漏未处理的异常 - 使用
Future.error()主动抛出异步异常
问题场景
在Dart异步编程中,以下代码可能无法正确捕获异常:
Future<void> fetchData() async {
final data = await http.get('https://api.example.com/data');
print('Data: ${data.body}');
}
void main() {
try {
fetchData();
} catch (e) {
print('Caught: $e'); // 无法捕获异步异常
}
}请解释原因并提供三种正确的异常处理方案。
原理说明
Dart的异步异常处理机制:
- 同步异常:立即抛出,可通过try/catch捕获
- 异步异常:存储在Future中,需通过注册回调或await捕获
async函数自动将同步异常包装为Future.error- 未捕获的异步异常会导致程序终止
解决方案
方案1:在async函数内部使用try/catch
Future<void> fetchData() async {
try {
final data = await http.get('https://api.example.com/data');
print('Data: ${data.body}');
} catch (e) {
print('Internal catch: $e'); // 捕获await抛出的异常
}
}方案2:使用Future.catchError()
void main() {
fetchData().catchError((e) {
print('External catch: $e'); // 捕获Future链中的异常
});
}方案3:结合await与try/catch
void main() async {
try {
await fetchData(); // await将异步异常转为同步异常
} catch (e) {
print('Await catch: $e');
}
}最佳实践
- 在
async函数中始终用try/catch包裹可能出错的await调用 - 为所有公开的异步API添加
.catchError()处理 - 使用
Future.error()传递结构化错误信息:Future.error({'code': 404, 'message': 'Not found'}) - 避免在catch块中返回
null,应返回合理的默认值或重新抛出
常见错误
- 错误1:在非async函数中尝试用try/catch捕获异步调用
// 错误示例 try { Future.delayed(Duration(seconds: 1), () => throw Exception()); } catch (e) {} // 无法捕获 - 错误2:忽略
async*生成器中的异常处理 - 错误3:在catchError后忘记返回恢复值导致链中断
扩展知识
- Zone:使用
runZonedGuarded全局捕获异步异常runZonedGuarded(() { fetchData(); }, (error, stack) { print('Global catch: $error'); }); - 错误类型:区分
Exception(可预期)和Error(程序错误) - 空安全:异步返回类型应明确声明可空性
Future<String?> fetchNullableData()