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 密集型工作
  • 使用流进行持续数据更新
  • 考虑缓存昂贵的异步操作的结果
相关推荐
帅次12 小时前
Objective-C面向对象编程:类、对象、方法详解(保姆级教程)
flutter·macos·ios·objective-c·iphone·swift·safari
小蜜蜂嗡嗡13 小时前
flutter flutter_vlc_player播放视频设置循环播放失效、初始化后获取不到视频宽高
flutter
孤鸿玉15 小时前
[Flutter小技巧] Row中widget高度自适应的几种方法
flutter
bawomingtian12315 小时前
FlutterView 源码解析
flutter
Zender Han18 小时前
Flutter 进阶:实现带圆角的 CircularProgressIndicator
flutter
nc_kai1 天前
Flutter 之 每日翻译 PreferredSizeWidget
java·前端·flutter
littlegnal1 天前
Flutter Add-to-app profiling
flutter
0wioiw01 天前
Flutter基础(FFI)
flutter
Georgewu10 天前
【HarmonyOS 5】鸿蒙跨平台开发方案详解(一)
flutter·harmonyos