如何在 map() 中使用异步代码(Flutter、Firestore)

J3n*_*sis 1 dart firebase flutter google-cloud-firestore

我正在使用 Flutter 和 Firestore 插件开发一个群聊应用程序。从数据库中获取数据并将快照转换为消息列表完全正常。但是现在我想将数据库中的 uid 转换为用户名(uid 及其用户名保存在 db 中)。这是我的代码:

final CollectionReference messagesCollection =
    Firestore.instance.collection('messages');

final CollectionReference usersCollection =
    Firestore.instance.collection('users');

Future<String> getUsernameByUID(String _uid) async {
  String username =
      await usersCollection.document(uid).get().then((querySnapshot) {
    return (querySnapshot.data["username"]);
  });
  return username;
}

List<Message> _messagesFromSnapshot(QuerySnapshot snapshot){
  return snapshot.documents.map((doc) {

    String username = await getUsernameByUID(doc.data["uid"]);

    return Message(
      text: doc.data["text"] ?? "",
      username: username ?? "",
      time: doc.data["time"] ?? "",
    );
  }).toList();
}


Stream<List<Message>> get messages {
  return messagesCollection
      .orderBy("time")
      .snapshots()
      .map(_messagesFromSnapshot);
}
Run Code Online (Sandbox Code Playgroud)

问题出在这一行,因为我无法在 map() 内运行此异步代码。

String username = await getUsernameByUID(doc.data["uid"]);
Run Code Online (Sandbox Code Playgroud)

有没有办法解决这个问题?提前致谢。

jam*_*lin 7

async函数必须返回 a Future,因此向async回调添加关键字意味着您的List.map()调用现在必须返回 aListFutures。

您可以使用以下方法将 a 转换List<Future<Message>>为 a :List<Message>Future.wait

Future<List<Message>> _messagesFromSnapshot(QuerySnapshot snapshot) async {
  var futures = snapshot.documents.map((doc) async {
    String username = await getUsernameByUID(doc.data["uid"]);

    return Message(
      text: doc.data["text"] ?? "",
      username: username ?? "",
      time: doc.data["time"] ?? "",
    );
  });

  return await Future.wait(futures);
}
Run Code Online (Sandbox Code Playgroud)

当然,Future.wait返回 aFuture并且必须是awaited,所以现在也_messagesFromSnapshot必须是async。异步是会传染的,然后会影响_messagesFromSnapshot.

由于messagesgetter 返回 aStream并且已经是异步的,我相信您可以使用Stream.asyncMap

Stream<List<Message>> get messages {
  return messagesCollection
      .orderBy("time")
      .snapshots()
      .asyncMap(_messagesFromSnapshot);
}
Run Code Online (Sandbox Code Playgroud)