【问题标题】:How to await a Map.forEach() in dart如何在飞镖中等待 Map.forEach()
【发布时间】:2021-09-15 18:20:24
【问题描述】:

我有一个返回地图的 Future。然后我需要使用该映射的值来等待另一个未来,然后在最后返回整个结果。问题是 dart 不能等待 async Map.forEach() 方法(参见:https://stackoverflow.com/a/42467822/15782390)。

这是我的代码:

调试控制台显示打印的项目如下:

flutter: getting journal entries
flutter: about to loop through pictures
flutter: getting picture
flutter: returning entries
flutter: [[....]] (Uint8List)
Future<List<JournalEntryData>> getJournalEntries() async {
    List<JournalEntryData> entries = [];
    print('getting journal entries');

    EncryptService encryptService = EncryptService(uid);

    await journal.get().then((document) {
      Map data = (document.data() as Map);
      print('about to loop through pictures');
      data.forEach((key, value) async {
        print('getting picture');
        dynamic pictures = await StorageService(uid).getPictures(key);
        print('done getting image');
        entries.add(JournalEntryData(
          date: key,
          entryText: encryptService.decrypt(value['entryText']),
          feeling: value['feeling'],
          pictures: pictures,
        ));
      });
    });
    print('returning entries');
    return entries;
  }
  Future getPictures(String entryID) async {
    try {
      final ref = storage.ref(uid).child(entryID);
      List<Uint8List> pictures = [];

      await ref.listAll().then((result) async {
        for (var picReference in result.items) {
          Uint8List? pic = await ref.child(picReference.name).getData();
          if (pic == null) {
            // TODO make no picture found picture
            var url = Uri.parse(
                'https://www.salonlfc.com/wp-content/uploads/2018/01/image-not-found-scaled-1150x647.png');
            var response = await http.get(url);
            pic = response.bodyBytes;
          }
          pictures.add(pic);
        }
      });
      return pictures;
    } catch (e) {
      print(e.toString());
      return e;
    }
  }

【问题讨论】:

  • 正如您链接到的问题所解释的那样,您应该使用Future.wait。或查看stackoverflow.com/a/63719805。
  • @jamesdlin 是的,确实如此。非常感谢!

标签: flutter dictionary dart asynchronous


【解决方案1】:

不要混合使用then 和await,因为它会变得相当混乱,并且事情不再像你想象的那样执行。 此外,forEach 方法的使用真的不应该用于复杂的逻辑,比如你正在做的事情。相反,请使用 for-each 循环。我已经尝试在这里重写getJournalEntries:

Future<List<JournalEntryData>> getJournalEntries() async {
  List<JournalEntryData> entries = [];
  print('getting journal entries');

  EncryptService encryptService = EncryptService(uid);

  final document = await journal.get();
  Map data = (document.data() as Map);
  print('about to loop through pictures');

  for (final mapEntry in data.entries) {
    final key = mapEntry.key;
    final value = mapEntry.value;

    print('getting picture');
    dynamic pictures = await StorageService(uid).getPictures(key);
    print('done getting image');
    entries.add(JournalEntryData(
      date: key,
      entryText: encryptService.decrypt(value['entryText']),
      feeling: value['feeling'],
      pictures: pictures,
    ));
  }
  print('returning entries');
  return entries;
}

这里是getPictures。我这里只删除了then的使用。

Future getPictures(String entryID) async {
  try {
    final ref = storage.ref(uid).child(entryID);
    List<Uint8List> pictures = [];
    final result = await ref.listAll();

    for (var picReference in result.items) {
      Uint8List? pic = await ref.child(picReference.name).getData();
      if (pic == null) {
        // TODO make no picture found picture
        var url = Uri.parse(
            'https://www.salonlfc.com/wp-content/uploads/2018/01/image-not-found-scaled-1150x647.png');
        var response = await http.get(url);
        pic = response.bodyBytes;
      }
      pictures.add(pic);
    }
    return pictures;
  } catch (e) {
    print(e.toString());
    return e;
  }
}

【讨论】:

  • 非常感谢。代码现在看起来更干净了。谢谢您的帮助!它也解决了我的问题!祝你有美好的一天!
【解决方案2】:

当您需要异步行为时必须使用 for 循环非常烦人,特别是在 Maps 上,因为正如另一个答案所示,这需要您遍历条目,然后将 key 和 value 取出它是这样的:

for (final mapEntry in data.entries) {
    final key = mapEntry.key;
    final value = mapEntry.value;
    ...
}

除此之外,您可以编写一个实用程序扩展来为您完成工作:

extension AsyncMap<K, V> on Map<K, V> {
  Future<void> forEachAsync(FutureOr<void> Function(K, V) fun) async {
    for (var value in entries) {
      final k = value.key;
      final v = value.value;
      await fun(k, v);
    }
  }
}

然后,你可以这样使用:

await data.forEachAsync((key, value) async {
    ...
});

好多了。

【讨论】:

  • 感谢您的帮助。这似乎是一个更优雅的解决方案。我希望 dart 默认允许在 Future 中使用类似的东西,双关语。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-28
  • 1970-01-01
  • 2019-05-30
  • 2019-05-07
  • 2021-03-11
  • 2020-11-05
  • 2021-09-05
相关资源
最近更新 更多