Использование циклов с фьючерсами в Dart

#dart #future

#dart #будущее

Вопрос:

Итак, у меня есть список файлов, и мне нужно запустить функцию для каждого элемента списка. По сути, я хочу сделать что-то вроде этого:

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

Но, очевидно, это не сработает, поскольку функция, которая возвращает Future, срабатывает асинхронно. Является ли мой единственный вариант чем-то вроде этого?

 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);
  

Редактировать:
Я полагаю, что важно больше контекста. Конечная цель — объединить несколько файлов в один объект JSON для отправки на сервер. Объект FileReader использует события для выполнения чтения, поэтому я использовал завершитель для создания функции-оболочки, которая обеспечивает будущее. Я мог бы позволить всем этим запускаться асинхронно, а затем запускать событие, которое отправляет его, когда все они будут выполнены, но это сравнительно большая настройка по сравнению с циклом for-each, который заставляет все это работать (если таковой существует, во всяком случае). Основная проблема заключается в необходимости запуска функции возврата в будущем для списка файлов, а затем выполнения действия, которое зависит от их завершения.

Комментарии:

1. В чем проблема с вашим первым примером? Какое значение имеет, выполняется ли функция асинхронно или нет?

2. Я отредактировал вопрос с дополнительной информацией.

Ответ №1:

Когда вам нужно дождаться завершения нескольких фьючерсов, и вас не волнует порядок, вы можете использовать Future.wait():

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

Если важен порядок, вы можете вместо этого использовать Future.forEach(), который ожидает завершения каждого Future перед переходом к следующему элементу:

 Future.forEach(files, functionThatReturnsAFuture)
  .then((response) => print('All files processed'));
  

Комментарии:

1. ЭТО идеально. Большое вам спасибо! Могу ли я спросить, что бы вы сделали, если бы порядок имел значение?

2. Рад помочь. Я добавил еще немного информации для решения этого случая.

3. И с этим у меня, наконец, достаточно репутации для ответов 1. Вы получаете мой первый 1!

4. Будущее. ожидание занимает итерацию, поэтому нет необходимости сначала составлять список. Просто сделайте Future.wait(files.map(functionThatReturnsAFuture)) .

5. @lrn Ах, спасибо, меня беспокоило, что Future.wait код был длиннее Future.forEach .

Ответ №2:

Dart поддерживает async / await с довольно долгого времени, что позволяет ему записывать как

 someFunc() async {
  for(File file in files) {
    await functionThatReturnsAFuture(file);
  }
}
  

Комментарии:

1. Я меняю принятый ответ на это, потому что именно так это и должно быть сделано сейчас.

2. Я так старался понять, как это работает. У меня больше внутренних методов. например, внутри функции, которая возвращает метод будущего, другой метод. Так что изначально не сработало. Затем я добавил ту же комбинацию async / await для всех внутренних методов. Затем начал работать, как ожидалось.

3. ожидание перед вызовом метода и асинхронность после подписи метода. Не пропустите это.

Ответ №3:

Эта библиотека может помочь 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();
});