Dart 异步指南:Future、Stream 和 Isolate —— 何时使用每个
发布: (2026年4月28日 GMT+8 21:01)
3 分钟阅读
原文: Dev.to
Source: Dev.to
为什么异步很重要
// ❌ BAD: synchronous call blocks the UI
void fetchData() {
final data = http.get('https://api.example.com/data'); // 2s wait
// UI freezes for 2 seconds
}
// ✅ GOOD: async keeps the UI responsive
Future fetchData() async {
final data = await http.get('https://api.example.com/data');
// UI continues responding while waiting
}
Future:一次性异步值
Future fetchUsername(String userId) async {
final response = await supabase
.from('profiles')
.select('username')
.eq('id', userId)
.single();
return response['username'] as String;
}
final username = await fetchUsername('user-123');
错误处理
try {
final username = await fetchUsername('user-123');
} on PostgrestException catch (e) {
debugPrint('DB error: ${e.message}');
} catch (e) {
debugPrint('Error: $e');
}
使用 Future.wait 并行执行
// Sequential: 2 seconds total
final profile = await fetchProfile(userId); // 1s
final settings = await fetchSettings(userId); // 1s
// Parallel: 1 second total
final results = await Future.wait([
fetchProfile(userId),
fetchSettings(userId),
]);
final profile = results[0] as Profile;
final settings = results[1] as Settings;
Stream:连续的异步值
// Supabase Realtime: receive messages as they arrive
Stream> watchMessages(String roomId) {
return supabase
.from('messages')
.stream(primaryKey: ['id'])
.eq('room_id', roomId)
.order('created_at');
}
// Use in a widget
StreamBuilder>
stream: watchMessages('room-1'),
builder: (context, snapshot) {
if (!snapshot.hasData) return const CircularProgressIndicator();
final messages = snapshot.data!;
return ListView.builder(
itemCount: messages.length,
itemBuilder: (_, i) => MessageTile(message: messages[i]),
);
},
);
构建自己的 Stream
Stream countDown(int from) async* {
for (int i = from; i >= 0; i--) {
yield i;
await Future.delayed(const Duration(seconds: 1));
}
}
await for (final count in countDown(10)) {
print(count); // 10, 9, 8, ... 0
}
Isolate:CPU 密集型工作在单独线程
// ❌ BAD: heavy work on main thread → jank
String parseHugeJson(String json) {
return processJson(json); // 3 seconds — UI freezes
}
// ✅ GOOD: offload to an Isolate (Flutter 3.7+)
Future parseHugeJsonInBackground(String json) async {
return Isolate.run(() => processJson(json));
}
针对 Flutter
Future parseHugeJson(String json) async {
return compute(processJson, json);
}
String processJson(String json) {
// runs in a background isolate
return jsonDecode(json).toString();
}
决策指南
One-time async value → Future / async‑await
Continuous stream of values → Stream / StreamBuilder
CPU‑intensive processing → Isolate.run / compute
Multiple concurrent tasks → Future.wait
与 Riverpod 结合
@riverpod
Future userProfile(UserProfileRef ref) async {
return fetchProfile(ref.watch(authUserIdProvider));
}
@riverpod
Stream> chatMessages(ChatMessagesRef ref, String roomId) {
return watchMessages(roomId);
}
总结
根据三个问题来选择:需要等待多长时间、会产生多少个值、以及工作有多 CPU 密集。
- 对于简单的一次性异步操作,直接使用
await。 - 当需要实时更新时,加入
Stream。 - 当 CPU 成为瓶颈时,使用
Isolate(或compute)。