【问题标题】:How to run multiple async functions in order they were called (FIFO?)如何按调用顺序运行多个异步函数(FIFO?)
【发布时间】:2019-08-30 03:22:42
【问题描述】:

我花了很多时间寻找解决方案,但由于我是 Dart 初学者,我无法自己找到它。 我想要实现的是为一些在应用程序运行时从代码中的不同点随机调用的异步函数(比如说,当用户在我的应用程序中点击一个按钮时)创建类似队列的东西。我希望它们按照调用顺序执行,所以基本上我有异步方法,例如 updateDate()updatePoints() 以及当用户点击按钮 X 时updateDate() 将被调用(添加到队列中),与 Y 和 updatePoints() 类似。当用户点击 i。 e. X, X, Y 我想按照这个确切的顺序运行 updateDate()、updateDate()、updatePoints()。当一项任务完成时,另一项任务正在开始。我想我不能使用 await 来实现这一点。任何提示将不胜感激!

【问题讨论】:

  • 如果一切都必须同步,为什么要使用异步?但你可以试试这个... doSomethingAsync().then((_) => doAnotherAsync());我不确定这会工作多少层
  • @stuckedoverflow 很好,如果一切都同步,就没有问题了。
  • 参见forEachAsync - 文档说:“为可迭代中的每个元素安排行动呼吁。不会超过 maxTasks 一次行动呼吁。”

标签: dart flutter dart-async


【解决方案1】:
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

【讨论】:

  • 感谢您的回复。这正是我一直在寻找的。我想我已经很接近了。
【解决方案2】:

以下代码在用于大型任务队列时可能是一种不好的做法,但如果您确定任务数组不会超过足够的大小 - 这可能会很好:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 2019-12-07
    • 1970-01-01
    • 2018-03-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多