How to apply an async function with .map() to each element of a list.
Thing you want to do
As a simple example, consider code that converts a Firestore DocumentSnapshot into a model class.
List<Model> models = docs.map((doc) => _fromDoc(doc)).toList();
I think it's common to prepare a method called _fromDoc like this, apply _fromDoc to each DocumentSnapshot with .map() on the list of DocumentSnapshots, and convert it to a list of model classes.
Now suppose the _fromDoc method was an async function.
For example:
List<Model> models = docs.map((doc) async => await _fromDoc(doc)).toList();
Don't you think it might work if you do it like this? Unfortunately this doesn't work 😓 If you think about it, you can see that
(doc) async => await _fromDoc(doc)
Since this is itself an async function, the return value is a Future<Model> instead of a Model.
That's why,
docs.map((doc) async => await _fromDoc(doc)).toList()
The type of this whole thing will be List<Future<Model>> instead of List<Model>.
in short,
docs.map((doc) => _fromDoc(doc)).toList()
After all, it's the same as the original.
How to ... ?
So what to do is use Future.wait().
Future.wait() converts Iterable<Future<T>> to Future<List<T>> , so if you await this, you can safely get the list of asynchronously resolved values.
List<Model> models = await Future.wait(docs.map((doc) => _fromDoc(doc)).toList());
Now you have applied the async function with .map() to each element of the list as intended 👍
Comments !