关于 dart-async-programming
指导开发者使用 Future 和 Stream 编写 Dart 异步代码,重点包括清晰的流程、错误处理、并发执行及流生命周期管理。
主要功能
- 01优先使用 async 和 await
- 02通过 try-catch 处理错误
- 03并发执行互不依赖的 Future
- 04使用 await for 消费流
- 05关闭 StreamController 实例
适用场景
- 01实现异步数据获取
- 02并发执行互不依赖的请求
- 03按顺序处理流事件
- 04避免 StreamController 资源泄漏
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ dart-lang/ skills --skill dart-async-programming安装后在 Claude Code 中输入/dart-async-programming确认已加载。
详细介绍
编写异步 Dart 代码
目录
核心指南
使用现代、声明式模式编写异步 Dart 代码。避免使用基于回调的旧式方法。假设所有网络、文件 I/O 和数据库操作都是异步的。
- 使用
async/await:始终优先使用async和await,而不是原始的.then()、.catchError()或.whenComplete()链式调用。这样可以简化执行流程并提升可读性。 - 妥善处理错误:将所有
await调用放在try-catch块中,以处理异常。不要依赖未处理的 Future 拒绝。 - 并发执行:使用
Future.wait同时启动并等待多个相互独立的 Future,而不是依次等待。 - 按顺序消费 Stream:消费 Stream 时,优先使用
await for,而不是.forEach()或.listen(),除非你确实需要低级订阅管理(例如暂停或恢复)。 - 防止内存泄漏:不再需要
StreamController时,或所属类被释放时,务必调用.close()。
处理 Future
顺序执行与并发执行
如果操作之间存在依赖关系,应依次等待。如果操作相互独立,则应同时启动,以优化执行时间。
顺序执行(存在依赖):
final user = await fetchUser(id);
final profile = await fetchProfile(user.profileId);
并发执行(相互独立):
final results = await Future.wait([
fetchUserData(id),
fetchUserPreferences(id),
fetchUserPermissions(id),
]);
错误处理
在 async 函数中始终使用标准的 try-catch-finally 块。
try {
final data = await fetchData();
process(data);
} on NetworkException catch (e) {
handleNetworkError(e);
} catch (e) {
handleGenericError(e);
} finally {
cleanupResources();
}
管理 Stream
消费 Stream
使用异步 for 循环(await for)按顺序处理 Stream 事件。它会自动处理 Stream 完成,并能与 try-catch 错误处理机制无缝配合。
try {
await for (final chunk in fileStream) {
processChunk(chunk);
}
} catch (e) {
logError('Stream processing failed: $e');
}
创建和管理 Stream
使用 StreamController 创建自定义 Stream 时,请确保妥善管理其生命周期,以避免内存泄漏。
class DataProvider {
final _controller = StreamController<Data>.broadcast();
Stream<Data> get dataStream => _controller.stream;
void updateData(Data newData) {
if (!_controller.isClosed) {
_controller.add(newData);
}
}
void dispose() {
_controller.close(); // Mandatory cleanup
}
}
工作流
任务进度:实现异步数据获取器
复制此清单,以跟踪异步数据获取逻辑的实现进度:
- 确定所需操作是顺序执行还是相互独立。
- 为函数添加
async关键字,并返回Future<T>。 - 将异步操作放在
try-catch块中。 - 如果操作相互独立,使用
Future.wait将 Future 组合起来。 - 如果操作需要顺序执行,则对每个步骤使用
await。 - 使用
on ExceptionType catch (e)处理特定异常。 - 运行验证器 -> 检查错误 -> 修复未处理的 Promise 拒绝。
任务进度:实现 Stream 消费者
复制此清单,以跟踪 Stream 消费逻辑的实现进度:
- 确认 Stream 来源(单订阅还是广播)。
- 将消费函数标记为
async。 - 将消费逻辑放在
try-catch块中。 - 实现
await for循环来遍历 Stream。 - 确保在满足特定终止条件时跳出循环或返回。
- 如果管理
StreamController,请实现dispose()或close()方法。
示例
反面模式与最佳实践:Future
反面模式(请勿使用):
Future<void> loadUserData() {
return fetchUser()
.then((user) {
return fetchProfile(user.id)
.then((profile) {
print('User: ${user.name}, Profile: ${profile.status}');
});
})
.catchError((error) {
print('Error: $error');
});
}
最佳实践:
Future<void> loadUserData() async {
try {
final user = await fetchUser();
final profile = await fetchProfile(user.id);
print('User: ${user.name}, Profile: ${profile.status}');
} catch (error) {
print('Error: $error');
}
}
反面模式与最佳实践:Stream
反面模式(请勿使用):
void processEvents(Stream<Event> eventStream) {
eventStream.listen(
(event) => handleEvent(event),
onError: (error) => print('Error: $error'),
);
}
最佳实践:
Future<void> processEvents(Stream<Event> eventStream) async {
try {
await for (final event in eventStream) {
handleEvent(event);
}
} catch (error) {
print('Error: $error');
}
}
相关技能
dart-idiomatic-usagedart-concurrency-isolates
评论
支持 Markdown