GluePear
GluePear

Reputation: 7735

Wrong order of execution in Flutter asynchronous code

I am having problems with futures in a Flutter app.

void saveCats() async {
  var cats = await convertToCats(_rawData);
  await DatabaseProvider.db.addCats(cats);
}

Future<List<Cat>> convertToCats(CatList catData) async {
  var cats = <Cat>[];
  await catData.forEach(key, value) async {
    var pos = await calculatePos();
    print('This should come first');
    cats.add(Cat(name: key, pos: pos);
  }
}

Future<int> calculatePos() async {
  return await DatabaseProvider.db.calculatePos();
}

database.dart:

Future<void> addCats(List<Cat> cats) async {
  print('This should come second');
  // Do adding stuff here
}

Future<int> calculatePos() async {
  // Some code to calculate the position
  return pos;
}

In the above code, the saveCats function is called when a button is tapped. This function converts some raw data to a list of Cat models, and adds them to the database. As part of this conversion process, it calculates the pos of the cat in a list. My problem is that I would expect that, of my two print statements, the one in the forEach loop should come before the one in the addCats database function. But instead they appear in reverse order. Where am I going wrong?

Upvotes: 0

Views: 686

Answers (2)

Richard Heap
Richard Heap

Reputation: 51770

forEach often doesn't do what you expect, because the provided function runs as a closure.

It's more natural when you want to iterate over a list doing something to each element to use for (or one of the more functional type methods like map).

It's not clear what type CatList is, so this is approximate, but you'll want something more like:

Future<List<Cat>> convertToCats(CatList catData) async {
  var cats = <Cat>[];
  for (var i = 0; i < catData.length; i++) {
    var key = catData[i].key;
    var pos = await calculatePos();
    print('This should come first');
    cats.add(Cat(name: key, pos: pos));
  }
  return cats;
}

or

Future<List<Cat>> convertToCats(CatList catData) async {
  return catData.map(...some mapping function...).toList();
}

Upvotes: 2

Adelina
Adelina

Reputation: 11941

You can't async/await in List.forEach() or Map.forEach() as both of them return void. Either use

await Future.forEach([1, 2, 3], (num) async {
    await asyncMethod(num);
  });

or something similar; https://api.flutter.dev/flutter/dart-async/Future/forEach.html

Upvotes: 3

Related Questions