1、基本的Async/Await
scss
Future<List<Product>> fetchProducts() async {
final response = await dio.get('请求地址'));
if (response.statusCode == 200) {
List<dynamic> data = jsonDecode(response.body);
return data.map((json) => Product.fromJson(json)).toList();
} else {
throw Exception('Failed to load products');
}
}
// 使用
void loadData() async {
try {
final products = await fetchProducts();
setState(() {
this.products = products;
});
} catch (e) {
showError('Failed to load products: $e');
}
}
2、使用 FutureBuilder
kotlin
FutureBuilder<List<Product>>(
future: fetchProducts(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Text('等待ing');
} else if (snapshot.hasError) {
return Text('错误: ${snapshot.error}');
} else if (snapshot.hasData) {
final products = snapshot.data!;
return ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) => ProductCard(product: products[index]),
);
} else {
return Text('没有数据');
}
},
)
3. 基于流的异步模式
scss
Stream<List<Message>> getMessageStream(String chatId) {
return FirebaseFirestore.instance
.collection('chats')
.doc(chatId)
.collection('messages')
.orderBy('timestamp', descending: true)
.limit(50)
.snapshots()
.map((snapshot) => snapshot.docs
.map((doc) => Message.fromJson(doc.data()))
.toList());
}
// 使用 StreamBuilder
StreamBuilder<List<Message>>(
stream: getMessageStream(chatId),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Text('等待ing');
} else if (snapshot.hasError) {
return Text('错误: ${snapshot.error}');
} else if (snapshot.hasData) {
final messages = snapshot.data!;
return ListView.builder(
itemCount: messages.length,
itemBuilder: (context, index) => MessageBubble(message: messages[index]),
);
} else {
return Text('没有数据');
}
},
)
最适合: 聊天应用程序、实时仪表板、实时通知和频繁变化的数据。
注意事项: 始终在 StatefulWidget 的 dispose() 方法中处理流订阅,以防止内存泄漏。
4. 并行执行
有时您需要多个异步操作同时运行而不是按顺序运行,
ini
Future<DashboardData> loadDashboardData() async {
// Start all futures in parallel
final userFuture = fetchUserProfile();
final statsFuture = fetchStatistics();
final notificationsFuture = fetchNotifications();
// Wait for all futures to complete
final results = await Future.wait([
userFuture,
statsFuture,
notificationsFuture,
]);
// Extract results
return DashboardData(
user: results[0],
statistics: results[1],
notifications: results[2],
);
}
注意事项: 只要任何一个操作失败,所有操作都会失败(无需额外处理)。
5. 顺序执行模式------当顺序很重要时
某些操作必须按照特定顺序进行,其中每个步骤都依赖于前一个步骤:
scss
Future<PaymentResult> processPayment(Order order) async {
final validatedOrder = await validateOrder(order);
final paymentIntent = await createPaymentIntent(validatedOrder);
final confirmedPayment = await confirmPayment(paymentIntent);
final receipt = await generateReceipt(confirmedPayment);
// Final result depends on all previous steps
return PaymentResult(
success: true,
receipt: receipt,
confirmationCode: confirmedPayment.confirmationCode,
);
}
关键见解: 当每个步骤都依赖于前一步的结果时使用此模式,但考虑将独立操作分解为并行执行。
6. 重试模式
比如网络操作失败。始终实施最大重试限制,并考虑针对不同类型的错误使用不同的重试策略。
dart
Future<T> retryAsync<T>(
Future<T> Function() operation, {
int maxAttempts = 3,
Duration delay = const Duration(seconds: 1),
}) async {
int attempts = 0;
while (true) {
attempts++;
try {
return await operation();
} catch (e) {
if (attempts >= maxAttempts) {
rethrow;
}
final backoffDelay = delay * attempts;
await Future.delayed(backoffDelay);
}
}
}
// 使用
Future<List<Product>> fetchProductsWithRetry() {
return retryAsync(
() => fetchProducts(),
maxAttempts: 5,
delay: Duration(seconds: 2),
);
}
7. 超时模式------防止无限期等待
设置合理的超时时间,确保操作不会无限期挂起:
csharp
Future<T> withTimeout<T>(
Future<T> future, {
Duration timeout = const Duration(seconds: 10),
T? fallbackValue,
}) async {
try {
return await future.timeout(timeout);
} on TimeoutException {
if (fallbackValue != null) {
return fallbackValue;
}
throw TimeoutException('Operation timed out', timeout);
}
}
// 使用
Future<SearchResults> searchProducts(String query) async {
return withTimeout(
performSearch(query),
timeout: Duration(seconds: 5),
fallbackValue: SearchResults.empty(),
);
}
场景: 用户发起的操作、搜索操作以及任何响应至关重要的功能。
注意事项: 不同的操作需要不同的超时时间;关键用户操作的超时时间应比后台进程的超时时间短,防止 UI 无限期挂起,允许在适当的时候使用后备值,改善慢速连接下的用户体验,可以与重试模式结合使用,需要小心处理超时错误,可能会取消最终会成功的操作
8. 防抖模式------防止过多的异步操作
对于搜索等的操作,去抖动可以防止过多的 接口 调用:
ini
Timer? _debounceTimer;
void searchWithDebounce(String query) {
if (_debounceTimer?.isActive ?? false) {
_debounceTimer!.cancel();
}
_debounceTimer = Timer(Duration(milliseconds: 500), () {
_performSearch(query);
});
}
Future<void> _performSearch(String query) async {
setState(() {
isLoading = true;
});
try {
final results = await searchService.search(query);
setState(() {
searchResults = results;
isLoading = false;
});
} catch (e) {
setState(() {
error = e.toString();
isLoading = false;
});
}
}
@override
void dispose() {
_debounceTimer?.cancel();
super.dispose();
}
优点:
- 防止用户输入时过多的 API 调用
- 减少服务器负载和电池使用量
- 通过更流畅的交互改善用户体验
- 对于搜索和过滤功能尤其有价值
缺点:
- 给用户交互带来轻微的延迟
- 需要仔细管理计时器状态
- 必须妥善处置以防止内存泄漏
最适合: 实时搜索、文本字段验证以及任何由频繁用户输入触发的功能。
注意事项: 适当的去抖动持续时间取决于您的使用情况 - 自动完成时较短(300-500 毫秒),更密集的操作时较长(700-1000 毫秒)。
9. CancelableOperation 模式------夺回控制权
当离开或想取消时,有时需要取消还需要运行的操作,使用onCancel
回调来清理任何不会因取消而自动释放的资源。
swift
class SearchController {
CancelableOperation<List<SearchResult>>? _searchOperation;
Future<List<SearchResult>> search(String query) async {
_searchOperation?.cancel();
_searchOperation = CancelableOperation.fromFuture(
_performSearch(query),
onCancel: () {
debugPrint('Search canceled: $query');
},
);
return _searchOperation!.value;
}
Future<List<SearchResult>> _performSearch(String query) async {
await Future.delayed(Duration(seconds: 1));
return searchApi.fetchResults(query);
}
void dispose() {
_searchOperation?.cancel();
}
}
场景: 搜索操作、大数据传输和在完成之前可能变得无关紧要的长时间计算。
注意事项: 并非所有操作都可以被有意义地取消,
10. 隔离模式------征服 CPU 密集型任务
对于可能阻塞 UI 线程的操作,隔离提供了真正的并行执行:
ini
Future<List<ImageData>> processImages(List<Uint8List> rawImages) async {
final processedImages = await compute(
_processImagesInIsolate,
rawImages,
);
return processedImages;
}
List<ImageData> _processImagesInIsolate(List<Uint8List> rawImages) {
final result = <ImageData>[];
for (final rawImage in rawImages) {
final processed = applyFilters(rawImage);
final metadata = extractMetadata(rawImage);
result.add(ImageData(
processedImage: processed,
metadata: metadata,
));
}
return result;
}
// 在组件里面使用
ElevatedButton(
onPressed: () async {
setState(() {
isProcessing = true;
});
final processed = await processImages(selectedImages);
setState(() {
processedImages = processed;
isProcessing = false;
});
},
child: Text('图像出路'),
)
最适合: 图像/视频处理、数据解析、加密/解密以及任何耗时超过约 16 毫秒(以维持 60fps)的 CPU 密集型任务。
注意事项: 使用该compute
函数进行简单的隔离操作,但考虑使用更复杂的隔离池进行多个并行操作。但是无法从隔离区访问 UI 或大多数 Flutter API
💡 总结 --- 大概在那些情况使用
以下是选择正确异步模式的简单决策框架:
对于 UI 驱动的操作:
- 使用 FutureBuilder/StreamBuilder 进行状态处理
- 对输入驱动操作应用去抖动
- 当导航可以中断操作时,使操作可取消
对于数据操作:
- 当操作独立时使用并行执行
- 当顺序很重要时使用顺序执行
- 始终实施超时并考虑重试网络操作
对于性能关键代码:
- 使用 isolate (隔离)进行 CPU 密集型工作
- 使用流进行持续数据更新
- 考虑缓存昂贵的异步操作的结果