Search code examples
dartflutterdart-async

How to run multiple async functions in order they were called (FIFO?)


I've spent many hours looking for the solution, but since I am Dart begginer, I couldn't find it out by myself. What I want to achieve is to create something like queue for some of the async functions that are called randomly (let's say, when user is tapping a button in my app) from different points in code while the app is running. I want them to be executed in the order they were called, so basically I have async methods such as updateDate() and updatePoints() and when the user is tapping button X the updateDate() is going to be called (added to queue), and similar with Y and updatePoints(). When the user taps i. e. X, X, Y I want to run updateDate(), updateDate(), updatePoints() in this exact order. When one task is complete, another one is starting. I guess I can't use await to achieve that. Any hints would be appreciated!


Solution

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

    Result:

    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