0
votes

In the following code I thought the f1 > f2 > f3 would be the invocation order, but only f1 is being invoked. How can I get the 3 functions to be invoked sequentially?

I have added the following to the main function and it works as expected but I want to know if there are other definitive ways of achieving the same results?

print('Starting main');
List<Future> futures=new List<Future>();
Future v1=f1();
Future v2=f2();
Future v3=f3();
futures.add(v1);
futures.add(v2);
futures.add(v3);
Future.wait(futures);
print('Leaving main');

import 'dart:async';

Duration d1 = new Duration(seconds: 5);
Duration d2 = new Duration(seconds: 10);
Duration d3 = new Duration(seconds: 15);

bool r1 = false;
bool r2 = false;
bool r3 = false;

void cb1() {
    print('Entering CB1');
    r1 = true;
    print('Leaving CB1');
}

void cb2() {
    print('Entering CB2');
    r2 = true;
    print('Leaving CB2');
}

void cb3() {
    print('Entering CB3');
    r3 = true;
    print('Leaving CB3');
}

Timer t1;
Timer t2;
Timer t3;

Future<bool> start1() {
    print('Entering start1');
    Completer<bool> r = new Completer();
    r.future.then((_) {
        while (!r1) {

        }
        print('Completing start1');
        r.complete(true);
    });

    print('Leaving start1');
    return r.future;
}

Future<bool> start2() {
    print('Entering start2');
    Completer<bool> r = new Completer();
    r.future.then((_) {
        while (!r2) {

        }
        print('Completing start2');
        r.complete(true);
    });

    print('Leaving start2');
    return r.future;
}

Future<bool> start3() {
    print('Entering start3');
    Completer<bool> r = new Completer();
    r.future.then((_) {
        while (!r3) {

        }
        print('Completing start3');
        r.complete(true);
    });

    print('Leaving start3');
    return r.future;
}

Future<bool> f1() {
    print('Entering f1');
    Completer<bool> result = new Completer();
    t1 = new Timer(d1, cb1);
    result.complete(start1());

    print('Leaving f1');
    return result.future;
}

Future<bool> f2() {
    print('Entering f2');
    Completer<bool> result = new Completer();
    t2 = new Timer(d2, cb2);
    result.complete(start2());

    print('Leaving f2');
    return result.future;
}

Future<bool> f3() {
    print('Entering f3');
    Completer<bool> result = new Completer();
    t3 = new Timer(d3, cb3);
    result.complete(start3());

    print('Leaving f3');
    return result.future;
}

void main() {
    print('Starting main');
    f1().then((_) {
        f2().then((_) {
            f3().then((_) {

            });
        });
    });
    print('Leaving main');
}
2
Your startX methods seem very weird. What is their purpose? Loop-waiting for a variable until it has a specific value is very bad style. You should use events of callbacks but never with an empty loop. - Günter Zöchbauer
hi there, it is just a test code to understand how the future mechanism works. i am struggling to get my head around the Future concept in dart.. i think i understand your cleaned up code mate...but will get back to you.... thanks very much buddy! - signtheta
If you have a specific question just return to SO! - Robert
how would you write code to call an async function in synced function and wait until the async func returns? - signtheta

2 Answers

2
votes

First of all you should clarify why you need this. I don't really get why you want them to be executed sequentially - you should give us some more information on the concept behind it.

Please give us some more information on what you want to accomplish! The following code does somehow what I think you want:

// I did some more cleanup to the code:

import 'dart:async';

Duration d1 = new Duration(seconds: 5);
Duration d2 = new Duration(seconds: 10);
Duration d3 = new Duration(seconds: 15);

Future<bool> f1() {
  print('Entering f1');
  Completer<bool> r = new Completer();
  new Timer(d1, () {
    r.complete(true);
  });
  print('Leaving f1');
  return r.future;
}

Future<bool> f2() {
  print('Entering f2');
  Completer<bool> r = new Completer();
  new Timer(d2, () {
    r.complete(true);
  });
  print('Leaving f2');
  return r.future;
}

Future<bool> f3() {
  print('Entering f3');
  Completer<bool> r = new Completer();
  new Timer(d3, () {
    r.complete(true);
  });
  print('Leaving f3');
  return r.future;
}

void main() {
    print('Starting main');
    f1().then((_) {
        f2().then((_) {
            f3().then((_) {

            });
        });
    });
    print('Leaving main');
}
2
votes

In start1, you return a future which is never completed. Basically, what you do is:

start1() {
  var r = new Completer();
  r.then.((_) { ... r.complete() ... });
  return r.future;
}

Since the only complete of r requires r to be completed, that won't happen. That means that the result of f1 will wait forever on the future returned by start1, and f1().then((_) ... will never get to the then callback. That's why nothing is happening.

You also have a busy-waiting loop while (!r1) {}. If you intend that to hang if r1 isn't true, then it works fine. Futures are not executed concurrently in Dart. You have to return to the event loop before any future callback is called, so if r1 is false when reaching the loop, it will stay false, because no other code will ever interrupt the loop.

If I understand what you want with start1, maybe try rewriting it to:

// Returns a future which completes when `r1` becomes true.
start1() {
  var r = new Completer();
  void check() {
    if (r1) {
      r.complete();
    } else {
      // We can't use scheduleMicrotask here, because an infinite microtask
      // loop would prevent the timer from firing.
      Timer.run(check);  // Check again later.
    }
  }
  check();
  return r.future;
}