My async call is returning before list is populated in forEach loop My async call is returning before list is populated in forEach loop flutter flutter

My async call is returning before list is populated in forEach loop


This code

Future<List<String>> readHeaderData() async {  List<String> l = new List();  List<String> files = await readHeaders(); // Gets filenames  files.forEach((filename) async {    final file = await File(filename);    String contents = await file.readAsString();    User user = User.fromJson(json.decode(contents));    String name = user.NameLast + ", " + user.NameFirst;    print(name);    l.add(name);  }  return l;}

returns the list l and then processes the asyc forEach(...) callbacks

If you change it to

Future<List<String>> readHeaderData() async {  List<String> l = new List();  List<String> files = await readHeaders(); // Gets filenames  for(var filename in files) {  /// <<<<==== changed line    final file = await File(filename);    String contents = await file.readAsString();    User user = User.fromJson(json.decode(contents));    String name = user.NameLast + ", " + user.NameFirst;    print(name);    l.add(name);  }  return l;}

the function will not return before all filenames are processed.

files.forEach((filename) async {

means that you can use await inside the callback, but forEach doesn't care about what (filename) async {...} returns.


Also possible

await Future.forEach(yourList, (T elem) async { ...async staff });


To expand on Günter's comment regarding using list.map(f), here's an example of converting a forEach call so that it works correctly.

Broken example

Incorrectly assumes forEach will wait on futures:

Future<void> brokenExample(List<String> someInput) async {      List<String> results;  someInput.forEach((input) async {    String result = await doSomethingAsync(input);    results.add(result);  });  return results;}

Corrected example

Waits on the async functions to complete, using Future.wait and .map():

Future<void> correctedExample(List<String> someInput) async {  List<String> results;  await Future.wait(someInput.map((input) async {    String result = await doSomethingAsync(input);    results.add(result);  }));  return results;}