【问题标题】:Why does my async function that returns a Future<int> stall at await for each?为什么我的返回 Future<int> 的异步函数会在等待时停止?
【发布时间】:2020-05-06 16:46:37
【问题描述】:

我使用这个函数的目标是返回一个整数,表示用户完成的所有习惯。我的数据库结构是习惯的集合,每个习惯都有一个包含其历史的子集合。下面的函数利用了一个习惯列表,并使用习惯的 ID 获取该习惯的历史流。我的问题是,当我尝试遍历每个习惯的历史记录时,它会停在await for。任何建议都将不胜感激,我仍在尝试完全理解流/异步函数。

Future<int> getCompleteHabits(User user, List<Habit> habits) async {
  int completed = 0;
  if(habits.isNotEmpty) {
    for(Habit habit in habits) {
      Stream<List<HabitHistory>> streamHistory = db.streamHabitHistory(user, habit.id);
      await for(var h in streamHistory){
        print(habit.title);
        print(h);
      }
      print("test");
    }
  }
  return completed;
}

但是,这个函数将添加到已完成的变量中,因为我无法访问我尚未访问的所有历史记录。

此函数将以下内容打印到控制台,但没有到达print("test")

flutter:晚上 11:30 之前上床睡觉

flutter:['HabitHistory' 实例,'HabitHistory' 实例,'HabitHistory' 实例,'HabitHistory' 实例,'HabitHistory' 实例]

【问题讨论】:

    标签: flutter dart google-cloud-firestore


    【解决方案1】:

    正如 Abion47 所说,流尚未关闭,因此等待永远不会完成。它正在等待新的事件。

    知道了这一点,我可以使用await streamHabitHistory(user, habit.id).first 来获取列表(因此它不会等待事件)。代码如下。

    Future<int> getCompleteHabits(User user, List<Habit> habits) async {
      int completed = 0;
      if(habits.isNotEmpty) {
        for(Habit habit in habits) {
          List<HabitHistory> history = await db.streamHabitHistory(user, habit.id).first;
          for (HabitHistory h in history) {
            completed = completed + h.completed.length;
          }
    
        }
      }
      return completed;
    }
    

    【讨论】:

    • first 在流上返回 Future。由于您已经在 async 方法中,因此可以删除 then;只需等待first 即可获得列表。 (我不建议将thenawait 混用,因为这会使代码难以理解。)
    • 哇,这很有意义,我现在要更新答案。我现在使用await db.streamHabitHistory(user, habit.id).first; 获取列表,它运行良好。
    【解决方案2】:

    来自documentaion on Streams

    流在其中没有更多事件时完成,并且接收事件的代码会收到通知,就像收到新事件的通知一样。当使用 await for 循环读取事件时,循环在流完成时停止。

    您的循环挂起的原因是流尚未关闭。它将继续挂起,直到流关闭或直到您在循环中执行 breakreturn 语句。

    【讨论】:

    • 哇,这很有道理,当你说 close 时,这与 dispose 一样吗?如果它被处理了,它会知道流已经完成了吗?我刚才也想出了一个解决方法,所以我也将添加它作为答案。
    • 看看我的回答,让我知道你的想法。
    • @AnthonySette 您不能以典型方式“关闭”流。流关闭的方式是其控制器触发“完成”事件。从implementation 来看,firestore 包从不费心这样做,而是让流在其侦听器取消订阅后进行垃圾收集。这在一定程度上是有道理的,因为 firestore 包中的流设计用于在附加的服务接收更改时获取实时更新。
    • 好吧,这是有道理的,这是真的,因为当对用户数据库的特定部分进行更改时,正在侦听相应流的应用程序部分会更新。非常感谢!
    猜你喜欢
    • 2021-10-16
    • 2021-01-02
    • 1970-01-01
    • 2016-01-08
    • 2022-01-16
    • 2011-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多