Flutter web Future .then/.whenComplete

Flutter web Future .then/.whenComplete

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

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;
}

(return 之前也会触发) 我这样使用这段代码:

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.)(和一个空列表)然后是列表的元素(姓名 1、姓名 2 ...) (3.)。 我有什么错?如何等待先收到列表? 感谢您的回答!

您需要在异步函数中使用await。我猜

Stream<FS.QuerySnapshot> qs =  
EventDistanceDataRepository().getStreamByEventId(eventId: eventId);

应该是

Stream<FS.QuerySnapshot> qs = await 
EventDistanceDataRepository().getStreamByEventId(eventId: eventId);

凡是需要很长时间的操作发生的地方都会得到 await 关键字。 Try the code labs to get better with async await

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

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

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

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

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

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

如果是这样重写你的代码

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

工作正常!最终代码是:

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