How to Async/await in List.forEach() in Dart

25,324

Solution 1

I don't think it's possible to achieve what you want with the forEach method. However it will work with a for loop. Example;

asyncOne() async {
  print("asyncOne start");
  for (num number in [1, 2, 3])
    await asyncTwo(number);
  print("asyncOne end");
}

Solution 2

You need to use Future.forEach.

main() async {
  print("main start");
  await asyncOne();
  print("main end");
}

asyncOne() async {
  print("asyncOne start");
  await Future.forEach([1, 2, 3], (num) async {
    await asyncTwo(num);
  });
  print("asyncOne end");
}

asyncTwo(num) async
{
  print("asyncTwo #${num}");
}

Solution 3

You can't use forEach for this because it doesn't actually look at the return values of its callbacks. If they are futures, they will just be lost and not awaited.

You can either do a loop like Steven Upton suggested, or you can use Future.wait if you want the operations to run simultaneously, not one after the other:

asyncOne() async {
  print("asyncOne start");
  await Future.wait([1, 2, 3].map(asyncTwo));
  print("asyncOne end");
}

Solution 4

I know this is an old question, but I'll leave here a new answer, hoping this help someone in the future.

You can use forEach for what you're trying to achieve by doing something like this:

  asyncOne() async {
  print("asyncOne start");
  await Future.forEach([1, 2, 3],(num) async {
    await asyncTwo(num);
  });
  print("asyncOne end");
}
Share:
25,324

Related videos on Youtube

aelayeb
Author by

aelayeb

Updated on May 11, 2022

Comments

  • aelayeb
    aelayeb almost 2 years

    I'm writing some kind of bot (command line application) and I'm having trouble with async execution when I'm using the "forEach" method. Here is a simplified code of what I'm trying to do :

    main() async {
      print("main start");
      await asyncOne();
      print("main end");
    }
    
    asyncOne() async {
      print("asyncOne start");
      [1, 2, 3].forEach(await (num) async {
        await asyncTwo(num);
      });
      print("asyncOne end");
    }
    
    asyncTwo(num) async
    {
      print("asyncTwo #${num}");
    }
    

    And here is the output :

    main start
    asyncOne start
    asyncOne end
    main end
    asyncTwo #1
    asyncTwo #2
    asyncTwo #3
    

    What I'm trying to get is :

    main start
    asyncOne start
    asyncTwo #1
    asyncTwo #2
    asyncTwo #3
    asyncOne end
    main end
    

    If someone knows what I'm doing wrong I would appreciate it.

    • Ουιλιαμ Αρκευα
      Ουιλιαμ Αρκευα over 3 years
      Asynchronous calls don't work with <List>.forEach(), you need to use traditional loops. Why? This article explains it very well. I just discovered that Dart and Node.JS are almost the same.
  • aelayeb
    aelayeb about 7 years
    That's what I was starting to think. Thank you for confirming it. I thought that "await" expression precedes whatever is surrounding it but oh well...
  • Grahambo
    Grahambo over 5 years
    This should be the approved answer.
  • skytect
    skytect almost 5 years
    For anyone reading this, do note that this unfortunately only works for iterables.
  • mike-gallego
    mike-gallego over 4 years
    Yesss this is so perfect on what I needed because of internet connection issues with the app. It'll load the list and add it, when it is complete, notify.
  • Rahul Sharma
    Rahul Sharma about 4 years
    You just saved me hours of debugging and searching over internet.
  • Mangesh Kadam
    Mangesh Kadam about 4 years
    this does not work with Future.delayed in asyncTwo method. output is main start asyncOne start asyncOne end main end asyncTwo #1 asyncTwo #2 asyncTwo #3
  • Keith DC
    Keith DC almost 4 years
    That is literally a subset of what @Stephane posted above.
  • Jules Lee
    Jules Lee over 3 years
    Perfect answer!
  • David Chopin
    David Chopin over 2 years
    Note that while this is the best approach, the compiler may not know the type of num within the block. So you may have to call something like await Future.forEach<int>(someIntList, (item) async {