#flutter #dart #dart-async
Вопрос:
У меня есть асинхронная функция, которая выполняет сетевой запрос, и я хочу убедиться, что вызовы функции ожидают завершения любых предыдущих вызовов, прежде чем выполнять сетевой запрос. Я также хочу убедиться, что вызовы функции приводят к сетевым запросам в том же порядке.
Я придумал базовое решение, используя a List<Completer>
. Ниже приведен упрощенный пример, который можно запустить на DartPad. Обратите внимание, что пример очень упрощен и просто содержит множество вызовов, чтобы проиллюстрировать идею — в реальном мире вызовы функции могут поступать из разных мест — таймеры, взаимодействие с пользователем и т. Д.
import 'dart:async';
int i = 0;
List<Completer> funcCompleters = [];
Future<void> func() async{
// Make sure that subsequent calls wait for us
Completer c = Completer();
funcCompleters.add(c);
// Wait for any previous calls
if( funcCompleters.length > 1 ) await funcCompleters[funcCompleters.length-2].future;
// Simulate a lengthy operation, such as a network request
await Future.delayed(Duration(milliseconds: 500));
// Generate some output so we can see what happens
i = 1;
print('i: $i funcCompleters.length: ${funcCompleters.length}');
// Let any queued calls execute
c.complete();
funcCompleters.remove(c);
}
void main() async {
await func();
func();
func();
Timer(Duration(milliseconds: 800), () => func());
await func();
func();
await func();
await func();
func();
func();
Timer(Duration(milliseconds: 1), () => func());
func();
}
Это работает, но неуклюже.
В принципе, идея состоит в том, чтобы поставить функцию в очередь для любого вызова к ней и выполнять вызовы один за другим.
Есть ли лучший способ сделать это?
Комментарии:
1. видеть
Future.forEach
2. @pskink Спасибо, хотя мне следовало бы пояснить, что пример кода очень упрощен и что в моем реальном приложении вызовы функции могут исходить из разных мест, таких как таймеры и взаимодействие с пользователем. Я отредактировал вопрос, чтобы было более ясно, что пример очень упрощен.
3. поэтому используйте
StreamController
иStream.asyncMap
— в документах говорится: «Создает новый поток с каждым событием данных этого потока, асинхронно сопоставленным с новым событием. Это действует как карта, за исключением того, что преобразование может вернуть будущее, и в этом случае этот поток ожидает завершения этого будущего, прежде чем продолжить свой результат».
Ответ №1:
Я думаю, что вам нужно заставить все функции ждать таким образом, чтобы никто не выполнял их раньше предыдущего, и теперь все функции будут выполняться в том же порядке, в котором вам нужно, если это ваша цель из этого вопроса
Ответ №2:
Просто используйте Stream.asyncMap
для ожидания фьючерсов по порядку
import 'dart:async';
final orderedFuturesController = StreamController<Future>();
Future preserveOrder(Future future) {
orderedFuturesController.add(future);
return future;
}
Future<void> anyAsyncFunction(int value) async => print(value);
Future<void> main() async {
final subscription = orderedFuturesController.stream
.asyncMap((future) async => await future)
.listen((_) {}, cancelOnError: false);
await preserveOrder(anyAsyncFunction(0));
preserveOrder(anyAsyncFunction(1));
await preserveOrder(anyAsyncFunction(2));
preserveOrder(anyAsyncFunction(3));
await orderedFuturesController.stream.isEmpty;
await subscription.cancel();
}