0

I recently was trying to do something like this,

NOTE: Focus on the print statements.

  List shipped = [], pending = [], completed = [], returned = [];
  List<OrderModel> mainOrdersList = [];

  @override
  void initState() {
    super.initState();
    getData();
  }

  Future getData() async {
    var results = await DatabaseHandler().fetchOrders("merchantId");
    results.docs.forEach((f) async {
      var products = await DatabaseHandler().fetchOrderedProducts(f.id);
      var productData = products.data();
      //add to mainOrdersList
      print("mainOrderList Length - ${mainOrdersList.length}");
    });
    //THE BELOW STATEMENT IS BEING EXCECUTED BEFORE THE COMPLETION OF THE FOR LOOP GIVEN ABOVE
    segregate();
    setState(() {});
  }

  void segregate() {
    print("segregating");
    for (int i = 0; i < mainOrdersList.length; i++) {
      mainOrdersList[i].productList.forEach((element) {
        //segregate on the basis of status like pending, shipped, completed, returned
      });
    }
  }

OUTPUT WITH FOREACH -

segregating
mainOrdersList Length - 10

Even though I am using await in forEach, still the statement below the forEach is being exceuted first. But if I use simple for loop, this doesn't happen and the code works perfectly as it should.

Replacing forEach with for,

  for (int i = 0; i < results.docs.length; i++) {
      var f = results.docs[i].data();
      var products = await DatabaseHandler().fetchOrderedProducts(f.id);
      var productData = products.data();
      //add to mainOrdersList
      print("mainOrderList Length - ${mainOrdersList.length}");
    }

OUTPUT WITH SIMPLE FOR -

mainOrdersList Length - 10
segregating

And I also observed that forEach was a bit faster than for.

Vega
  • 27,856
  • 27
  • 95
  • 103
Mayur Agarwal
  • 1,448
  • 1
  • 14
  • 30
  • 2
    I think this is the best explanation for your problem. https://stackoverflow.com/questions/63719374/how-to-wait-for-foreach-to-complete-with-asynchronous-callbacks – Meet Prajapati Nov 11 '21 at 05:28
  • But I'm observing one thing, when I used forEach the list was updated very fast, but now after using normal for loop, the process is slower. – Mayur Agarwal Nov 11 '21 at 07:57

2 Answers2

2

default forEach not async operation, you must replace it with :

await Future.forEach(elements, (element) async {
  await element.someThing();
});
DJafari
  • 12,955
  • 8
  • 43
  • 65
0

try with a simple login.

Future getData() async {
bool isAsyncComplete = false; //add this line
    var results = await DatabaseHandler().fetchOrders("merchantId");
    results.docs.forEach((f) async {
      var products = await DatabaseHandler().fetchOrderedProducts(f.id);
      var productData = products.data();
      //add to mainOrdersList
      print("mainOrderList Length - ${mainOrdersList.length}");
      
      isAsyncComplete = true; //add this line
    
     });
    //THE BELOW STATEMENT IS BEING EXCECUTED BEFORE THE COMPLETION OF THE FOR LOOP GIVEN ABOVE 
     if(isAsyncComplete){. //add this line
         segregate();
         setState(() {});
     }
  
  }
Rohit Chaurasiya
  • 597
  • 5
  • 12