Dart: Dart 异步编程 — Future / async-await 详解
异步让程序不等待 — 一个 I/O 操作 3 秒,异步让 CPU 去干别的,而不是傻等。
1. 你将学到
- Future 的生命周期:pending / completed / failed
- async / await 语法糖与错误处理
- Future 组合:Future.wait / Future.any / Future.forEach
- Completer:手动控制 Future 完成
- Bob 场景:DataPipeline 并发请求多个电商 API
2. 一个开发者的真实故事
(1) 痛点:顺序请求导致页面加载 12 秒
Bob 的 DataPipeline 需要从 3 个 API 获取数据:订单(3 秒)、产品(2 秒)、客户(2 秒)。他最初用顺序请求:3 + 2 + 2 = 7 秒。加上数据库查询(5 秒),整个报表生成需要 12 秒。用户体验极差,SaaS 客户抱怨"太慢了"。
(2) Future.wait 并发的解法
用 Future.wait 让 3 个 API 请求并发执行,总时间取决于最慢的那个:3 秒。加上并发数据库查询,整个报表生成缩短到 4 秒。
// Sequential: 3 + 2 + 2 = 7 seconds
final orders = await fetchOrders(); // 3s
final products = await fetchProducts(); // 2s
final customers = await fetchCustomers(); // 2s
// Concurrent: max(3, 2, 2) = 3 seconds
final results = await Future.wait([
fetchOrders(),
fetchProducts(),
fetchCustomers(),
]);
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
(3) 收益
- Future.wait 并发让 API 调用从 7 秒缩短到 3 秒,整体 4 秒
- async/await 让异步代码看起来像同步代码,可读性提升
- 完善的错误处理让网络异常不再导致程序崩溃
3. Future 基础
(1) Future 生命周期
sequenceDiagram participant Bob participant API1 participant API2 participant API3 Bob->>API1: fetchOrders() Bob->>API2: fetchProducts() Bob->>API3: fetchCustomers() Note over Bob: Future.wait concurrent API1-->>Bob: 1.2M orders API2-->>Bob: 500K products API3-->>Bob: 300K customers Bob->>Bob: merge & analyze
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:创建与使用 Future
import 'dart:async';
// Create a Future that completes after a delay
Future``<String>`` fetchOrder() async {
await Future.delayed(const Duration(seconds: 2));
return 'ORD-001: \$1500.00 USD';
}
// Future with error
Future``<String>`` fetchOrderWithRetry() {
return Future.delayed(const Duration(seconds: 1), () {
throw Exception('Network timeout');
});
}
void main() async {
// Pending → Completed
print('Fetching order...');
final order = await fetchOrder();
print(order);
// Pending → Failed
try {
await fetchOrderWithRetry();
} catch (e) {
print('Error: $e');
}
}
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
| Future 状态 | 含义 |
|---|---|
| pending | 未完成,等待中 |
| completed with value | 成功完成,携带值 |
| completed with error | 失败完成,携带异常 |
4. async / await 详解
(1) 基础语法
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:async/await 基础
import 'dart:async';
Future``<double>`` calculateOrderTotal(String orderId) async {
// await pauses execution until Future completes
final amount = await fetchAmount(orderId);
final taxRate = await fetchTaxRate(orderId);
return amount * (1 + taxRate);
}
Future``<double>`` fetchAmount(String orderId) async {
await Future.delayed(const Duration(milliseconds: 500));
return 1500.0;
}
Future``<double>`` fetchTaxRate(String orderId) async {
await Future.delayed(const Duration(milliseconds: 300));
return 0.08;
}
void main() async {
final total = await calculateOrderTotal('ORD-001');
print('Total: \$${total.toStringAsFixed(2)} USD');
}
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
(2) 错误处理
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:async/await 错误处理
import 'dart:async';
Future``<String>`` fetchApiData(String endpoint) async {
await Future.delayed(const Duration(seconds: 1));
if (endpoint.contains('invalid')) {
throw Exception('API error: $endpoint not found');
}
return 'Data from $endpoint';
}
Future``<void>`` robustFetch(String endpoint) async {
try {
final data = await fetchApiData(endpoint);
print('Success: $data');
} on Exception catch (e) {
print('Exception: $e');
} finally {
print('Fetch completed for $endpoint');
}
}
void main() async {
await robustFetch('orders'); // Success
await robustFetch('invalid-endpoint'); // Exception
}
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
| 错误处理方式 | 语法 | 适用场景 |
|---|---|---|
| try-catch | try { await f(); } catch (e) {} |
需要恢复 |
| catchError | f().catchError((e) => ...) |
函数式风格 |
| onError | f().then(..., onError: ...) |
简单回调 |
5. Future 组合
(1) Future.wait — 并发等待
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:Future.wait 并发
import 'dart:async';
Future<List``<String>``> fetchOrders() async {
await Future.delayed(const Duration(seconds: 3));
return ['ORD-001', 'ORD-002', 'ORD-003'];
}
Future<List``<String>``> fetchProducts() async {
await Future.delayed(const Duration(seconds: 2));
return ['Laptop', 'Mouse', 'Keyboard'];
}
Future<List``<String>``> fetchCustomers() async {
await Future.delayed(const Duration(seconds: 2));
return ['Alice', 'Bob', 'Charlie'];
}
void main() async {
// Concurrent: max(3, 2, 2) = ~3 seconds
final stopwatch = Stopwatch()..start();
final results = await Future.wait([
fetchOrders(),
fetchProducts(),
fetchCustomers(),
]);
stopwatch.stop();
print('Orders: ${results[0]}');
print('Products: ${results[1]}');
print('Customers: ${results[2]}');
print('Time: ${stopwatch.elapsedMilliseconds}ms');
}
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:Future.wait 错误处理
import 'dart:async';
Future``<String>`` riskyFetch(String name, bool shouldFail) async {
await Future.delayed(const Duration(seconds: 1));
if (shouldFail) throw Exception('$name failed');
return '$name data';
}
void main() async {
// Future.wait fails fast - if any fails, the whole thing fails
try {
await Future.wait([
riskyFetch('API-1', false),
riskyFetch('API-2', true), // This one fails
riskyFetch('API-3', false),
]);
} catch (e) {
print('Future.wait failed: $e');
}
// Preserve individual results with eagerError: false
final results = await Future.wait(
[
riskyFetch('API-1', false).then((v) => Result.success(v)),
riskyFetch('API-2', true).then((v) => Result.success(v)).catchError((e) => Result.failure(e.toString())),
riskyFetch('API-3', false).then((v) => Result.success(v)),
],
);
for (final r in results) {
print(r.isSuccess ? 'OK: ${r.data}' : 'FAIL: ${r.error}');
}
}
class Result``<T>`` {
final T? data;
final String? error;
final bool isSuccess;
Result.success(this.data) : error = null, isSuccess = true;
Result.failure(this.error) : data = null, isSuccess = false;
}
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
(2) Future.any — 竞速
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:Future.any 竞速
import 'dart:async';
Future``<String>`` fetchFromCache() async {
await Future.delayed(const Duration(milliseconds: 100));
return 'Cache: ORD-001 data';
}
Future``<String>`` fetchFromApi() async {
await Future.delayed(const Duration(seconds: 2));
return 'API: ORD-001 data';
}
Future``<String>`` fetchFromDb() async {
await Future.delayed(const Duration(milliseconds: 500));
return 'DB: ORD-001 data';
}
void main() async {
// Returns the FIRST to complete
final fastest = await Future.any([
fetchFromCache(),
fetchFromApi(),
fetchFromDb(),
]);
print('Fastest: $fastest'); // Cache: ORD-001 data
}
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
(3) Future.forEach — 顺序迭代
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:Future.forEach
import 'dart:async';
Future``<void>`` processOrder(String orderId) async {
await Future.delayed(const Duration(milliseconds: 500));
print('Processed: $orderId');
}
void main() async {
final orders = ['ORD-001', 'ORD-002', 'ORD-003'];
// Process sequentially
await Future.forEach(orders, processOrder);
print('All orders processed');
}
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
| 组合方法 | 行为 | 并发 | 适用场景 |
|---|---|---|---|
Future.wait |
全部完成 | 并发 | 批量请求 |
Future.any |
第一个完成 | 并发 | 竞速/降级 |
Future.forEach |
顺序完成 | 顺序 | 依赖顺序的操作 |
6. Completer 手动控制
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:Completer
import 'dart:async';
// Manual Future control with Completer
class ApiService {
final Completer``<String>`` _initCompleter = Completer``<String>``();
Future``<String>`` get initialized => _initCompleter.future;
void onConnected(String serverInfo) {
if (!_initCompleter.isCompleted) {
_initCompleter.complete(serverInfo);
}
}
void onError(Object error) {
if (!_initCompleter.isCompleted) {
_initCompleter.completeError(error);
}
}
}
void main() async {
final service = ApiService();
// Simulate async initialization
Future.delayed(const Duration(seconds: 1), () {
service.onConnected('Server v3.0.1, 1,000,000 records');
});
print('Waiting for initialization...');
final info = await service.initialized;
print('Connected: $info');
}
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
7. Bob 场景:并发 API 请求
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:DataPipeline 并发数据获取
import 'dart:async';
// Simulated API calls
Future<List<Map<String, dynamic>>> fetchOrders() async {
await Future.delayed(const Duration(seconds: 2));
return [
{'id': 'ORD-001', 'amount': 1500.0, 'category': 'Electronics'},
{'id': 'ORD-002', 'amount': 3200.0, 'category': 'Electronics'},
{'id': 'ORD-003', 'amount': 890.0, 'category': 'Clothing'},
];
}
Future<Map<String, double>> fetchProductPrices() async {
await Future.delayed(const Duration(seconds: 1));
return {'Laptop': 1299.99, 'Mouse': 29.99, 'Keyboard': 79.99};
}
Future<List``<String>``> fetchCustomerNames() async {
await Future.delayed(const Duration(seconds: 1));
return ['Alice', 'Bob', 'Charlie'];
}
// Concurrent data fetching with error handling
Future``<void>`` generateReport() async {
final stopwatch = Stopwatch()..start();
try {
// Fetch all data concurrently
final results = await Future.wait([
fetchOrders().then((v) => ('orders', v)).catchError((e) => ('orders', null)),
fetchProductPrices().then((v) => ('products', v)).catchError((e) => ('products', null)),
fetchCustomerNames().then((v) => ('customers', v)).catchError((e) => ('customers', null)),
]);
stopwatch.stop();
print('=== DataPipeline Report ===');
print('Fetch time: ${stopwatch.elapsedMilliseconds}ms');
for (final (key, value) in results) {
if (value != null) {
print('$key: OK (${value is List ? value.length : value.length} items)');
} else {
print('$key: FAILED');
}
}
} catch (e) {
print('Report generation failed: $e');
}
}
void main() async {
await generateReport();
}
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
8. 完整示例:DataPipeline 异步数据处理
// ============================================
// DataPipeline Async Data Processing
// Future, async/await, and concurrent operations
// ============================================
import 'dart:async';
// Simulated data sources
Future<List<Map<String, dynamic>>> fetchOrders({int delay = 2}) async {
await Future.delayed(Duration(seconds: delay));
return [
{'id': 'ORD-001', 'amount': 1500.0, 'status': 'completed', 'category': 'Electronics'},
{'id': 'ORD-002', 'amount': 50.0, 'status': 'completed', 'category': 'Books'},
{'id': 'ORD-003', 'amount': 3200.0, 'status': 'pending', 'category': 'Electronics'},
{'id': 'ORD-004', 'amount': 890.0, 'status': 'completed', 'category': 'Clothing'},
];
}
Future<List<Map<String, dynamic>>> fetchProducts({int delay = 1}) async {
await Future.delayed(Duration(seconds: delay));
return [
{'name': 'Laptop', 'price': 1299.99, 'category': 'Electronics'},
{'name': 'Mouse', 'price': 29.99, 'category': 'Electronics'},
{'name': 'Novel', 'price': 12.99, 'category': 'Books'},
];
}
Future``<double>`` fetchTaxRate(String region) async {
await Future.delayed(const Duration(milliseconds: 500));
return switch (region) {
'US' => 0.08,
'EU' => 0.20,
'UK' => 0.15,
_ => 0.10,
};
}
// Async pipeline with concurrent operations
class AsyncPipeline {
final String name;
String status = 'idle';
AsyncPipeline({required this.name});
Future<Map<String, dynamic>> run({String region = 'US'}) async {
status = 'running';
final stopwatch = Stopwatch()..start();
try {
// Step 1: Concurrent data fetch
final (orders, products, taxRate) = await (
fetchOrders(),
fetchProducts(),
fetchTaxRate(region),
).wait;
// Step 2: Process orders
final completedOrders = orders
.where((o) => o['status'] == 'completed')
.toList();
// Step 3: Calculate revenue
final revenue = completedOrders.fold``<double>``(
0, (sum, o) => sum + (o['amount'] as double));
final taxAmount = revenue * taxRate;
final totalWithTax = revenue + taxAmount;
// Step 4: Group by category
final byCategory = <String, double>{};
for (final order in completedOrders) {
final cat = order['category'] as String;
final amt = order['amount'] as double;
byCategory.update(cat, (v) => v + amt, ifAbsent: () => amt);
}
stopwatch.stop();
status = 'completed';
return {
'pipeline': name,
'region': region,
'taxRate': taxRate,
'totalOrders': orders.length,
'completedOrders': completedOrders.length,
'revenue': revenue,
'tax': taxAmount,
'totalWithTax': totalWithTax,
'byCategory': byCategory,
'processingTime': stopwatch.elapsedMilliseconds,
'status': status,
};
} catch (e) {
status = 'failed';
rethrow;
}
}
}
void main() async {
final pipeline = AsyncPipeline(name: 'E-Commerce Analytics');
print('=== Starting DataPipeline ===');
final report = await pipeline.run(region: 'US');
print('\n=== Report ===');
print('Pipeline: ${report['pipeline']}');
print('Region: ${report['region']}');
print('Tax Rate: ${(report['taxRate'] as double * 100).toStringAsFixed(1)}%');
print('Total Orders: ${report['totalOrders']}');
print('Completed: ${report['completedOrders']}');
print('Revenue: \$${(report['revenue'] as double).toStringAsFixed(2)} USD');
print('Tax: \$${(report['tax'] as double).toStringAsFixed(2)} USD');
print('Total: \$${(report['totalWithTax'] as double).toStringAsFixed(2)} USD');
print('Time: ${report['processingTime']}ms');
print('\nBy Category:');
for (final entry in (report['byCategory'] as Map<String, double>).entries) {
print(' ${entry.key}: \$${entry.value.toStringAsFixed(2)} USD');
}
}
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
输出:
=== Starting DataPipeline ===
=== Report ===
Pipeline: E-Commerce Analytics
Region: US
Tax Rate: 8.0%
Total Orders: 4
Completed: 3
Revenue: $2440.00 USD
Tax: $195.20 USD
Total: $2635.20 USD
Time: 2000ms
By Category:
Electronics: $1500.00 USD
Books: $50.00 USD
Clothing: $890.00 USD
❓ 常见问题
Q:async 函数的返回值类型是什么? A:async 函数自动将返回值包装为 Future。声明 `Future``
``` 返回类型,函数内直接 return T 即可。
Q:await 只能在 async 函数中使用吗? A:是的。await 只能在 async 函数或 async 生成器中使用。Dart 3.5+ 支持顶层 await(仅在 Dart 脚本中)。*
Q:Future.wait 中某个 Future 失败会怎样? A:默认情况下,任何一个 Future 失败,Future.wait 立即抛出该异常(其他 Future 继续运行但结果被忽略)。可用 eagerError: false 等待所有完成。
Q:async/await 和 .then() 有什么区别? A:功能等价,但 async/await 更可读(线性流程),.then() 更函数式(链式调用)。推荐日常用 async/await,简单转换用 .then()。
Q:Completer 什么时候用? A:当你需要手动控制 Future 的完成时机时用 Completer。常见场景:事件回调转 Future、WebSocket 消息、第三方库回调。大多数场景直接用 async/await 即可。
Q:Future 是多播还是单播? A:Future 是单播的 — 只能被一个 await 或 .then() 消费。多播需要用 Stream 或 asStream()。
Q:如何实现超时控制? A:用 Future.timeout() 方法。如
await fetchApi().timeout(Duration(seconds: 5), onTimeout: () => defaultData)。
📖 小节
- Future 代表异步计算的最终结果,有 pending/completed/failed 三种状态
- async/await 是 Future 的语法糖,让异步代码读起来像同步代码
- Future.wait 并发执行多个 Future,总时间取决于最慢的
- Future.any 竞速取最快,Future.forEach 顺序执行
- Completer 手动控制 Future 完成,适用于回调转 Future 场景
📝 作业
- 基础题(难度⭐):写 3 个返回 Future 的函数(分别延迟 1/2/3 秒),用 async/await 顺序调用,测量总时间;再用 Future.wait 并发调用,对比时间。
- 进阶题(难度⭐⭐):实现一个带重试的异步请求函数
fetchWithRetry(url, retries: 3, backoff: Duration),失败时按指数退避重试,超过次数后抛出异常。 - 挑战题(难度⭐⭐⭐):用 Completer 实现一个简单的"请求-响应"协议:发送请求后等待对应的响应,支持超时控制。模拟一个消息总线,多个请求可以并发发送。