1

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 ?

4

4 回答 4

2

我想这不是你想要的,但据我所知,没有办法阻止执行,所以你必须使用回调。

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
}

你当然可以将回调作为参数传递而不是硬编码它,因为函数是 Dart 中的第一类成员。

于 2014-03-11T18:07:33.783 回答
1

轮询对于异步来说不是很好。最好等待必须完成的事情的信号。

Günter Zöchbauer 的回答向您展示了如何通过使用计时器进行采样来进行轮询。

作为替代方案,最好不要完成布尔运算,而是在您准备好时完成另一个未来。这是忙轮询,一旦结果返回就会再次轮询,这可能比您需要的更密集。如果您不需要尽快获得结果,则使用基于计时器的轮询会更有效。

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

(代码没有真正测试过,因为我没有你的 requestServer)。

于 2014-03-12T07:20:28.897 回答
1

当您想要构建返回 Futures 的函数时,有时使用 Completers 很有用。认为 requestServer() 也存在于 Future 中,因此您将威胁到作为 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;
    });
于 2014-03-13T01:51:57.460 回答
0

我在TestUtil库中使用这样的函数:

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

然后在我的测试代码中,我将执行以下操作:

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

编辑:

请注意,如果您在testWidgets测试中使用它,则必须做一些额外的事情,因为它依赖于发生的真正异步工作:

  await tester.runAsync<bool>(
      () => TestUtil.waitUntilTrue(() => myObj.isLoaded),
      additionalTime: Duration(seconds: 5));
于 2021-02-08T00:02:02.893 回答