Question

I launch a request to a server with a future "requestServer". I would like to poll a system for a specific value (passed from false to true, when request is done) and return when finished.

Code could be like that, but "while" synchronous and "checkOperation" is asynchronous?

return requestServer().then((operation) {
  var done = false;
  while (done)
    return checkOperation(operation).then((result) {
      done = (result == true);
    });
    sleep(10);
  }
});

Any ideas ?

Was it helpful?

Solution

I guess this is not exactly what you want but as far as I know there is no way to block execution so you have to use callbacks.

void main(List<String> args) {

  // polling
  new Timer.periodic(new Duration(microseconds: 100), (t) {
    if(isDone) {
      t.cancel();
      someCallback();
    }
  });

  // set isDone to true sometimes in the future
  new Future.delayed(new Duration(seconds: 10), () => isDone = true);
}

bool isDone = false;

void someCallback() {
  print('isDone: $isDone');
  // continue processing
}

You can of course pass the callback as parameter instead of hardcode it, because functions are first class members in Dart.

OTHER TIPS

Polling doesn't work very well for async. It is better to wait for a signal from the thing that must complete.

Günter Zöchbauer's answer shows you how to poll anyway, by sampling with a timer.

As an alternative, it would be better to not have a boolean done, but instead complete another future when you are ready. This is busy-polling, which polls again as soon as a result comes back, which may be more intensive than you need. Using timer based polling can be more efficient if you don't need the result as soon as possible.

return requestServer().then((operation) {
  var completer = new Completer();
  void poll(result) {     
    if (!result) { 
      operation.then(poll, onError: completer.completeError);
    } else {
      completer.complete();
    }
  }
  poll(false);
  return completer.future;
});

(Code not really tested, since I don't have your requestServer).

When you want build functions that return Futures, it is sometimes useful to use Completers. Think that requestServer() is living in the Future too, so you will have threat the result as a Future.

    return requestServer().then((operation) {

      // This is necessary then you want to control async 
      // funcions.
      Completer completer = new Completer();

      //
      new Timer.periodic(const Duration(seconds: 10), (_) {
        checkOperation(operation).then((result) {

          // Only when the result is true, you pass the signal
          // that the operation has finished.
          // You can alse use `completer.complete(result)` if you want
          // to pass data inside of the future.
          if (result == true) completer.complete();
        });
      });

      // You return the future straight away.
      // It will be returned by requestServer();
      return completer.future;
    });

I use a function like this in a TestUtil library:

  static Future<bool> waitUntilTrue(bool Function() callback,
      {Duration timeout: const Duration(seconds: 2),
      Duration pollInterval: const Duration(milliseconds: 50)}) {
    var completer = new Completer<bool>();

    var started = DateTime.now();

    poll() {
      var now = DateTime.now();
      if (now.difference(started) >= timeout) {
        completer.completeError(Exception('timed out in waitUntilTrue'));
        return;
      }
      if (callback()) {
        completer.complete(true);
      } else {
        new Timer(Duration(milliseconds: 100), () {
          poll();
        });
      }
    }

    poll();
    return completer.future;
  }

And then in my test code I'll do something like:

await TestUtil.waitUntilTrue(() => someObj.isDone);

Edit:

Note that if you're using this in a testWidgets test, you have to do a little extra, since it relies on real async work happening:

  await tester.runAsync<bool>(
      () => TestUtil.waitUntilTrue(() => myObj.isLoaded),
      additionalTime: Duration(seconds: 5));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top