首页 > 解决方案 > Flutter web Future .then/.whenComplete

问题描述

请帮助我理解,为什么这段代码不起作用!我尝试从 Stream (Firestore) 中获取数据,并将这些数据放到一个列表中。我想等到列表准备好,然后用这个列表做点什么。但是 .then 或 .whenComplete 在列表准备好之前触发......这是创建列表并返回它的函数:

Future<List<EventDistance>> getEventsDistanceList(String eventId) async{
  Stream<FS.QuerySnapshot> qs =  EventDistanceDataRepository().getStreamByEventId(eventId: eventId);
  List<EventDistance> dList = [];
  EventDistance eventDistance;
   qs.forEach((document)  {
     document.forEach((docs) {
      eventDistance = eventDistanceFromJson(docs.data());
      dList.add(eventDistance);
      print(eventDistance.Name); //(3.) only for testing, to see if docs is not empty
    }
    );

  });
  print('return'); //(1.) only for testing, to see when return is fired
  return dList;
}

(返回之前也会触发)我使用此代码:

Future<List<EventDistance>> dList = getEventsDistanceList(filteredList[index].id );
dList.then((value) {
  print('value: $value'); //(2.) only for testing,to see if the returned list is empty or not (empty :-( )
  doSomething;
});

当我运行时,我首先收到'return'(1.),然后是'value:null'(2.)(和一个空列表),然后是列表的元素(Name1,Name2 ...)(3.) . 我错了什么?如何等待先收到列表?感谢您的回答!

标签: flutterfuture

解决方案


要对异步操作更有信心,请阅读 Didier Boelens 的完美文章

让我们检查一下您的代码中发生了什么

您的 getEventsDistanceList() 例程是纯同步的 - 它的所有内容都逐步同步运行

  1. 同步订阅 Stream inqs.forEach并设置回调侦听器,该侦听(document) { ... }器将在每个流项目上触发somewhere in future
  2. 同步调用print('return')被触发
  3. 终于getEventsDistanceList()回来了
  4. 你听这个 Future 返回,getEventsDistanceList()直到它完成,然后then()被调用print('value: $value')
  5. 接收到第一个流项目并使用 print(eventDistance.Name) 触发回调

第五步将重复新项目,直到流完成或以错误结束(参见 Stream.forEach 实现)

我想你只需要第一个 Stream 项目(如果没有,请不要犹豫在评论中联系我)

如果是这样,请重写您的代码

EventDistanceDataRepository()
  .getStreamByEventId(eventId: eventId)
  .first
  .then((document) => document.map((docs) => eventDistanceFromJson(docs.data())).toList())
  .then((value) { doSomething;});

我更喜欢可读性更高的await符号

final FS.QuerySnapshot document = await EventDistanceDataRepository()
  .getStreamByEventId(eventId: eventId)
  .first;

final List<EventDistance> listOfEvents = document.docs.map((e) => eventDistanceFromJson(e.data())).toList();

doSomething with this list

推荐阅读