Using loops with Futures in Dart
Asked Answered
C

3

12

Okay, so I have a List of Files and I need to run a function on each member of the list. I essentially want to do something like this:

for(File file in files) {
    functionThatReturnsAFuture(file);
}

But obviously this won't work, since the function that returns a Future fires of asynchronously. Is my only option something like this?

List<File> files = new List<File>();
// Add files somewhere

Future processFile(int i) {
   return new Future.sync(() {
       //Do stuff to the file
       if(files.length>i+1) {
           return processFile(i+1);
       }
   });
}

processFile(0);

EDIT: I suppose more context is important. The end goal is to combine several files into a single JSON object for submitting to a server. The FileReader object uses events to perform a read, so I used a Completer to create a wrapper function that provides a Future. I could let all of these run asynchronously, and then fire off an event that submits it when they are all done, but that's comparatively a lot of setup vs. a for-each-loop that makes it all work (if one exists, anyway). The core issue is needing to run a Future-returning function on a List of files and then perform an action that depends on them all having completed.

Cusp answered 26/6, 2014 at 18:29 Comment(2)
What's the problem with your first example? What does it matter if the function runs asynchronously or not?Ply
I edited the question with more information.Cusp
S
15

Dart supports async/await since quite some time which allows it to write as

someFunc() async {
  for(File file in files) {
    await functionThatReturnsAFuture(file);
  }
}
Stumpage answered 20/7, 2017 at 7:43 Comment(3)
I'm changing the accepted answer to this, because this is how it should be done now.Cusp
I was so struggled, to understand how this works. I am having more inner methods. like inside functionThatReturnsAFuture method another method. So not worked initially. Then i added the same combination of async/ await for all inner method. Then started working as expected.Winebaum
await in front of method call and async after method signature. Don't miss these.Winebaum
P
39

When you need to wait for multiple Futures to complete and you don't care about the order, you can use Future.wait():

Future.wait(files.map(functionThatReturnsAFuture))
  .then((List response) => print('All files processed'));

If order is important you can use Future.forEach() instead which waits for each Future to be completed before moving to the next element:

Future.forEach(files, functionThatReturnsAFuture)
  .then((response) => print('All files processed'));
Ply answered 26/6, 2014 at 19:6 Comment(5)
THAT is perfect. Thank you very much! Might I ask what you would do if the order did matter?Cusp
Glad to help. I've added some more info to address that case.Ply
And with that, I finally have enough reputation to +1 answers. You get my first +1!Cusp
The Fjuture.wait takes an Iterable, so there is no need to make a List first. Just do Future.wait(files.map(functionThatReturnsAFuture)).Amari
@Amari Ah thanks, it was bothering me that the Future.wait code was longer than Future.forEach.Ply
S
15

Dart supports async/await since quite some time which allows it to write as

someFunc() async {
  for(File file in files) {
    await functionThatReturnsAFuture(file);
  }
}
Stumpage answered 20/7, 2017 at 7:43 Comment(3)
I'm changing the accepted answer to this, because this is how it should be done now.Cusp
I was so struggled, to understand how this works. I am having more inner methods. like inside functionThatReturnsAFuture method another method. So not worked initially. Then i added the same combination of async/ await for all inner method. Then started working as expected.Winebaum
await in front of method call and async after method signature. Don't miss these.Winebaum
S
-1

This library can help https://pub.dartlang.org/packages/heavylist

HeavyList<File> abc = new HeavyList<File>([new File(), new File(), ]);
abc.loop(new Duration(seconds: 1), (List<File> origin) {
print(origin);
}, (File item, Function resume) {
  //simulating an asynchronous call
  print(item);
  //move to next item
  resume();
});
Start answered 10/9, 2018 at 23:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.