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)。
0 浏览
Back to Blog

相关文章

阅读更多 »

消息与通知工具比较 (2026)

PostgreSQL LISTEN/NOTIFY ✅ 优点 - 内置于数据库,无需额外安装。 - 严格事务化:只有在数据满足条件时才会发送消息。