Как запустить несколько асинхронных функций по порядку их вызова (FIFO?) - PullRequest
1 голос
/ 09 апреля 2019

Я потратил много часов на поиски решения, но, поскольку я начинающий Дарт, я не смог найти его сам. Чего я хочу добиться, так это создать нечто вроде очереди для некоторых асинхронных функций, которые вызываются случайным образом (скажем, когда пользователь нажимает кнопку в моем приложении) из разных точек кода во время работы приложения. Я хочу, чтобы они выполнялись в том порядке, в котором они были вызваны, поэтому в основном у меня есть асинхронные методы, такие как updateDate () и updatePoints () , а когда пользователь нажимает кнопку X, updateDate () будет вызываться (добавляться в очередь) и аналогично Y и updatePoints (). Когда пользователь касается i. е. X, X, Y Я хочу запустить updateDate (), updateDate (), updatePoints () в этом точном порядке. Когда одна задача завершена, начинается другая. Я думаю, что я не могу использовать ожидание, чтобы достичь этого. Любые советы будут оценены!

Ответы [ 2 ]

2 голосов
/ 09 апреля 2019

Следующий код может быть плохой практикой при использовании в большой очереди задач, но если вы уверены, что массив задач не будет превышать адекватный размер - это может работать просто отлично:

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 {...} closure к каждой 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 ]
});
1 голос
/ 09 апреля 2019
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

...