[Flutter] How to apply async function with map to each element of list?

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 !

Links

Social