题目
Dart异步编程:如何正确处理Future与Stream的错误?
信息
- 类型:问答
- 难度:⭐⭐
考点
异步编程, Future错误处理, Stream错误处理, async/await, 异常捕获
快速回答
在Dart中正确处理异步错误的要点:
- 使用
try/catch捕获async/await中的同步和异步错误 - 为
Future添加catchError回调处理链式错误 - 通过
Stream的listen方法的onError参数捕获流错误 - 使用
runZonedGuarded捕获未处理的异步异常 - 避免忽略错误和重复捕获同一异常
1. 核心原理
Dart的异步错误处理机制基于事件循环:
- Future:表示单次异步操作结果,错误通过
Future.error或抛出异常产生 - Stream:处理连续数据流,错误作为独立事件在流中传递
- 未捕获的异步错误会导致程序终止
2. Future错误处理
方法1:async/await + try/catch
void fetchData() async {
try {
var data = await http.get('https://api.example.com/data');
print('Data: $data');
} catch (e, s) {
print('Error: $e');
print('Stack trace: $s');
}
}方法2:catchError回调
http.get('https://api.example.com/data')
.then((data) => print('Data: $data'))
.catchError((e, s) {
print('Future error: $e');
print('Stack trace: $s');
});3. Stream错误处理
Stream countStream() async* {
for (int i = 0; i < 5; i++) {
if (i == 3) throw Exception('Stream error at $i');
yield i;
}
}
void main() {
countStream().listen(
(data) => print('Received: $data'),
onError: (e, s) => print('Stream error: $e'),
cancelOnError: false // 错误后是否继续监听
);
} 4. 全局错误捕获
void main() {
runZonedGuarded(() {
Future.error('Uncaught async error');
}, (error, stack) {
print('Global error: $error');
});
}5. 最佳实践
- 优先使用async/await:使异步代码更接近同步风格
- 始终捕获根异常:避免使用空的catch块
- 记录堆栈跟踪:通过
StackTrace参数获取错误源头 - 区分错误类型:针对不同异常采取不同恢复策略
6. 常见错误
- ❌ 忽略
catchError导致未处理异常 - ❌ 在
then中抛出异常但未后续处理 - ❌ 混淆同步
try/catch与异步错误捕获范围 - ❌ 未处理
StreamSubscription的取消逻辑导致内存泄漏
7. 扩展知识
- Error vs Exception:Dart中所有错误均继承自
Error,但通常用Exception表示可恢复错误 - Isolate错误:跨Isolate通信需通过
SendPort发送错误对象 - StreamController:手动添加错误事件
controller.addError(error)