Flutter中async*函数使用yield*后for循环不继续执行问题
问题根因
yield*的语义是完全委托目标Stream的事件推送,只有被委托的Stream触发done完成事件后,当前生成器函数才会继续执行yield*之后的逻辑。
你代码中调用的snapshots()是Firestore提供的实时监听流,这个流会长期存活:只要不主动取消订阅,它会持续推送集合的实时变更,永远不会主动触发完成事件。因此第一次循环执行到yield*时,函数会永久停在第一个partner的流监听逻辑上,永远不会进入下一轮循环处理剩余的列表元素。
解决方案
根据实际业务需求二选一即可:
场景1:需要持续监听所有partner的referral集合实时变更
如果要同时监听所有partner的集合变化,不要用yield*逐个等待流完成,直接合并所有子流统一推送即可:
import 'dart:async'; // 其余业务依赖导入省略 static Stream<List<Referral>> streamRefs( List<Map<String, dynamic>> partnerLocations) async* { final streamGroup = StreamGroup<List<Referral>>(); for (var partner in partnerLocations) { debugPrint("初始化partner监听: $partner"); final singlePartnerStream = FirebaseFirestore.instance .collection('partners') .doc('kenya') .collection(partner['category']) .doc(partner['branchID']) .collection("referrals") .snapshots() .map((snapshot) => snapshot.docs .map((document) => Referral.fromJson( document.data(), document.id, partner['branchID'], partner['category'], )) .toList()); streamGroup.add(singlePartnerStream); } yield* streamGroup.stream; }
如果需要把所有partner的referral数据合并为一个全量列表推送,可以维护一个Map记录每个partner对应的最新数据,任意子流有更新时重新拼接全量列表再yield即可。
场景2:只需要一次性拉取每个partner的referral数据,不需要实时监听
这种场景直接用get()替换snapshots()获取一次性查询结果即可,循环会正常顺序执行:
static Stream<List<Referral>> streamRefs( List<Map<String, dynamic>> partnerLocations) async* { for (var partner in partnerLocations) { debugPrint("拉取partner数据: $partner"); final snapshot = await FirebaseFirestore.instance .collection('partners') .doc('kenya') .collection(partner['category']) .doc(partner['branchID']) .collection("referrals") .get(); final refList = snapshot.docs .map((document) => Referral.fromJson( document.data(), document.id, partner['branchID'], partner['category'], )) .toList(); yield refList; } }
内容的提问来源于stack exchange,提问作者user10675368
相关产品推荐
相关产品推荐

