如何在dart中等待Map.forEach()



我有一个Future,它返回一个映射。然后,我需要使用该映射的值来等待另一个未来,然后在最后返回整个结果。问题是dart不能等待asyncMap.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;
}
}

当你需要异步行为时,特别是在Maps上,必须使用for循环是很烦人的,因为正如另一个答案所示,这需要你迭代条目,然后像这样去掉keyvalue

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 {
...
});

好多了。

不要混合使用thenawait,因为它会变得相当混乱,而且事情不再像您想象的那样执行。此外,forEach方法的使用实际上不应该用于像您正在做的那样复杂的逻辑。相反,请为每个循环使用。我尝试在这里重写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;
}
}

最新更新