你提供的这段内容是对 Dart 中异步编程(asynchronous programming) 的官方说明,重点讲解了如何使用 async/await 处理 Future 和 Stream。下面我将为你系统化梳理核心要点,并补充一些最佳实践和常见误区,帮助你更清晰地掌握 Dart 异步编程。
🧩 一、Future 与 async/await
1. 什么是 Future?
- 表示一个尚未完成的异步操作。
- 最终会成功(返回值)或失败(抛出异常)。
- 常见于 I/O 操作:文件读取、网络请求、数据库查询等。
2. 使用 await 获取结果
dart
Future<void> checkVersion() async {
var version = await lookUpVersion(); // 暂停执行,直到 Future 完成
print('Version: $version');
}✅ 关键规则:
await只能在async函数中使用。async函数总是返回Future<T>(即使你写的是void,实际是Future<void>)。
3. 错误处理:try/catch
dart
try {
var version = await lookUpVersion();
} on Exception catch (e) {
print('Failed to get version: $e');
}💡
await会自动将Future的错误转换为可被catch捕获的异常。
4. 多次使用 await
dart
void main() async {
final entry = await findEntryPoint();
final code = await runExecutable(entry, args);
await flushThenExit(code);
}- 每个
await会顺序等待,但不会阻塞整个 Dart 线程(事件循环仍可处理其他事件)。
5. main() 函数也可以是 async
dart
void main() async {
print('Version: ${await lookUpVersion()}');
}⚠️ 常见陷阱:调用
async函数但不await,可能导致逻辑未按预期执行。dartvoid main() async { checkVersion(); // ❌ 未 await,可能在 main 结束前未完成 print('Done'); }✅ 解决方案:启用
unawaited_futureslint 规则,或显式await。
📦 二、Stream 与 await for
1. 什么是 Stream?
- 表示随时间多次发出值的异步序列(如:传感器数据、WebSocket 消息、用户点击流)。
- 与
Future(单值)不同,Stream是多值的。
2. 使用 await for 遍历流
dart
void main() async {
await for (final request in requestServer) {
handleRequest(request);
}
}✅ 执行流程:
- 等待流发出一个值;
- 执行循环体;
- 重复,直到流关闭。
3. 何时使用 await for?
- ✅ 适合:需要处理完整数据流(如日志处理、批量数据导入)。
- ❌ 不适合:UI 事件监听(如按钮点击),因为 UI 事件流通常是“无限”的,
await for会阻塞后续代码。
🔁 对于 UI 事件,应使用
Stream.listen():dartbutton.onClick.listen((event) => handleTap(event));
4. 提前退出
- 使用
break或return可取消订阅流,避免内存泄漏。
🛠 三、async 函数的返回类型
| 同步函数 | 异步函数(加 async) |
|---|---|
String foo() | Future<String> foo() async |
void bar() | Future<void> bar() async |
💡 即使函数体没有显式返回
Future,加async后 Dart 会自动包装返回值为Future。
示例:
dart
// 同步
String getVersion() => '1.0';
// 异步(未来可能变耗时)
Future<String> getVersion() async => '1.0'; // 自动包装为 Future🚫 四、常见误区与最佳实践
| 误区 | 正确做法 |
|---|---|
在非 async 函数中使用 await | 编译报错!确保函数标记为 async |
调用 async 函数但不 await | 可能导致竞态条件;要么 await,要么用 unawaited()(谨慎) |
在 UI 中对无限流用 await for | 改用 .listen(),避免阻塞 |
忘记处理 Future 错误 | 总是用 try/catch 或 .catchError() |
📚 五、总结:Dart 异步编程模型
| 特性 | 说明 |
|---|---|
| 单线程 + 事件循环 | 所有 Dart 代码运行在单线程,通过事件循环实现“并发” |
Future | 表示单个异步结果 |
Stream | 表示多个异步结果(事件流) |
async/await | 语法糖,让异步代码像同步一样易读 |
| 错误处理 | 使用 try/catch 捕获异步异常 |
| 并发扩展 | 真正并行需用 Isolates(另见并发文档) |
✅ 推荐学习路径:
- 掌握
Future+async/await - 学习
Stream+await for/.listen() - 了解
Isolate实现 CPU 并行 - 在 Flutter 中结合
FutureBuilder/StreamBuilder构建 UI
如需动手练习,可参考 Dart 官方 Asynchronous Programming Tutorial。