Я провел много часов в поисках решения, но, поскольку я начинающий пользователь Dart, я не смог найти его самостоятельно. Чего я хочу добиться, так это создать что-то вроде очереди для некоторых асинхронных функций, которые вызываются случайным образом (скажем, когда пользователь нажимает кнопку в моем приложении) из разных точек кода во время работы приложения. Я хочу, чтобы они выполнялись в том порядке, в котором они были вызваны, поэтому в основном у меня есть асинхронные методы, такие как дата обновления() и апдейтпойнтс(), и когда пользователь нажимает кнопку X, будет вызываться updateDate() (добавляется в очередь) и аналогично с Y и updatePoints(). Когда пользователь нажимает i. е. X, X, Y Я хочу запустить updateDate(), updateDate(), updatePoints() именно в этом порядке. Когда одна задача завершена, начинается другая. Думаю, я не могу использовать await для этого. Любые подсказки будут оценены!
@stuckedoverflow хорошо, если бы все было синхронизировано, проблем бы не было.
см. forEachAsync - в документах говорится: «Расписание вызовов к действию для каждого элемента в iterable. Одновременно будет ожидать не более maxTasks вызовов к действию».
import 'dart:async';
import 'dart:collection';
import 'dart:math';
Future<void> main() async {
_simulateRealWork();
}
Scheduler _scheduler = Scheduler();
class Scheduler {
bool _scheduled = false;
Queue<Future Function()> _queue = Queue<Future Function()>();
void schedule(Future Function() task) {
_queue.add(task);
if (!_scheduled) {
_scheduled = true;
Timer(Duration(seconds: 0), _execute);
}
}
Future _execute() async {
while (true) {
if (_queue.isEmpty) {
_scheduled = false;
return;
}
var first = _queue.removeFirst();
await first();
}
}
}
void _simulateRealWork() {
var maxPeriod = 5;
var count = 5;
for (var i = 0; i < count; i++) {
print('Timer $i');
var random = Random();
Timer(Duration(seconds: random.nextInt(maxPeriod)), () {
print('Scheduled work $i');
Future work() async {
print('Started work $i');
await Future.delayed(Duration(seconds: random.nextInt(maxPeriod)));
print('Ended work $i');
}
_scheduler.schedule(work);
});
}
}
Результат:
Timer 0
Timer 1
Timer 2
Timer 3
Timer 4
Scheduled work 2
Started work 2
Scheduled work 0
Scheduled work 3
Ended work 2
Started work 0
Scheduled work 1
Scheduled work 4
Ended work 0
Started work 3
Ended work 3
Started work 1
Ended work 1
Started work 4
Ended work 4
Спасибо за ваш ответ. Это именно то, что я искал. Я думаю, что я был довольно близок, хотя.
Следующий код может быть плохой практикой при использовании в большой очереди задач, но если вы уверены, что массив задач не превысит адекватный размер - это может работать нормально:
Future<List<T>> runOneByOne<T>(List<T Function()> list) {
if (list.isEmpty) {
return Future.value(null);
}
Future task = Future<T>.microtask(list.first);
final List<T> results = [];
for (var i = 1; i < list.length; i++) {
final func = list[i];
task = task.then((res) { results.add(res); return Future<T>.microtask(func); });
}
return task.then((res) { results.add(res); return results; });
}
Он выполняет функции одну за другой в исходном порядке, оборачивая одну Future
в другую. results
массив используется для хранения возвращаемых значений, возвращая все значения в конце.
Выполнение останавливается и бросает, если наткнулся на ошибку. В этом случае массив результатов теряется. Вы можете добавить try {...}
закрытие к каждой microtask
оболочке, чтобы игнорировать ошибки и возвращать null
в этой конкретной задаче, сохраняя другие значения в массиве results
.
Пример использования:
runOneByOne<int>([
() { print("First"); return 1; },
() { print("Second"); return 2; },
() { print("Third"); return 3; },
]).then((results) {
print(results); // List<int> [ 1, 2, 3 ]
});
если все должно быть синхронизировано, зачем использовать асинхронность? но вы можете попробовать это... doSomethingAsync().then((_) => doAnotherAsync()); Я не уверен, насколько глубоко это будет работать.