Skip to content

你提供的这段内容是对 Dart 中异步编程(asynchronous programming) 的官方说明,重点讲解了如何使用 async/await 处理 FutureStream。下面我将为你系统化梳理核心要点,并补充一些最佳实践和常见误区,帮助你更清晰地掌握 Dart 异步编程。


🧩 一、Futureasync/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,可能导致逻辑未按预期执行。

dart
void main() async {
  checkVersion(); // ❌ 未 await,可能在 main 结束前未完成
  print('Done');
}

✅ 解决方案:启用 unawaited_futures lint 规则,或显式 await


📦 二、Streamawait for

1. 什么是 Stream

  • 表示随时间多次发出值的异步序列(如:传感器数据、WebSocket 消息、用户点击流)。
  • Future(单值)不同,Stream多值的。

2. 使用 await for 遍历流

dart
void main() async {
  await for (final request in requestServer) {
    handleRequest(request);
  }
}

执行流程

  1. 等待流发出一个值;
  2. 执行循环体;
  3. 重复,直到流关闭。

3. 何时使用 await for

  • ✅ 适合:需要处理完整数据流(如日志处理、批量数据导入)。
  • ❌ 不适合:UI 事件监听(如按钮点击),因为 UI 事件流通常是“无限”的,await for 会阻塞后续代码。

🔁 对于 UI 事件,应使用 Stream.listen()

dart
button.onClick.listen((event) => handleTap(event));

4. 提前退出

  • 使用 breakreturn取消订阅流,避免内存泄漏。

🛠 三、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(另见并发文档)

推荐学习路径

  1. 掌握 Future + async/await
  2. 学习 Stream + await for / .listen()
  3. 了解 Isolate 实现 CPU 并行
  4. 在 Flutter 中结合 FutureBuilder / StreamBuilder 构建 UI

如需动手练习,可参考 Dart 官方 Asynchronous Programming Tutorial