Flutter 的Async/Await 日常使用

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 密集型工作
  • 使用流进行持续数据更新
  • 考虑缓存昂贵的异步操作的结果
相关推荐
vvilkim4 小时前
Flutter 常用组件详解:Text、Button、Image、ListView 和 GridView
前端·flutter
getapi4 小时前
flutter把 pubspec.yaml 中的name改成了新的值
flutter·macos·cocoa
vvilkim4 小时前
Flutter 命名路由与参数传递完全指南
前端·flutter
程序员老刘4 小时前
iOS 26 beta1 真机无法执行hot reload
flutter·ios·客户端
无知的前端11 小时前
Flutter开发,GetX框架路由相关详细示例
android·flutter·ios
造梦师1 天前
flutter基础面试知识汇总(二)
flutter
vvilkim1 天前
Flutter 核心概念:深入理解 StatelessWidget 与 StatefulWidget
开发语言·javascript·flutter
sunly_1 天前
Flutter:导航背景固定在顶部,下拉分页布局
开发语言·javascript·flutter