如何在 Dart 中取消延迟的未来?

How to make a delayed future cancelable in Dart?

假设在 Dart/Flutter 中您有以下代码:

void myOperation() {
  // could be anything
  print('you didn't cancel me!');
}

请注意,操作本身不是异步的并且是无效的 -- return 什么都没有。

我们希望它在将来的某个时候执行,但我们也希望能够取消它(因为已请求一个新的操作来取代它)。

我是这样开始的:

Future.delayed(Duration(seconds: 2), myOperation())

...但这是不可取消的。

您如何准确安排该“操作”,同时又使其可取消?

我在想...我们可以像这样修改代码:

Future.delayed(Duration(seconds: 2), () {
    if (youStillWantThisToExecute) {
        print('you didn't cancel me!');
    }
});

但这并不是很好,因为它依赖于一个“全局”布尔值...所以如果布尔值被翻转为 false,则不会完成任何操作,即使是最近请求的操作,也就是我们想要的操作完成。

如果有一种方法可以创建任意数量的操作实例并逐一取消它们,或者为每个操作分配一个唯一的 id,而不是使用一个布尔值控制是否执行...以具有“mostRecentId”int 或在执行之前检查的内容。

总之...

CancelableOperation 的名字似乎很有前途。

所以,我查看了它的文档:

CancelableOperation.fromFuture(Future inner, {FutureOr onCancel()}) Creates a CancelableOperation wrapping inner. [...] factory

但老实说,这让我可怜的脑袋很痛。

我已经查阅了其他文章、问题和答案,但它们都是某些特定(和复杂)上下文的一部分,并且在任何地方都找不到一个简单的例子。

有没有办法通过将延迟的未来包装在其他 class 中来取消它?

能否请更有经验的人提供至少一个简单、完整、经过验证的在 DartPad 中编译的示例?

谢谢。

使用CancalableOperation不会阻止print('hello');执行,即使您取消也是如此。它所做的是取消(丢弃)结果(在您的情况下为无效)。我将使用 CancalableOperationCancalableFuture.

给你 2 个例子

CancelableOperation 例子

    final delayedFuture = Future.delayed(
      Duration(seconds: 2),
      () {
        return 'hello';
      },
    );

    final cancellableOperation = CancelableOperation.fromFuture(
      delayedFuture,
      onCancel: () => {print('onCancel')},
    );

    cancellableOperation.value.then((value) => {
          // Handle the future completion here
          print('then: $value'),
        });
    cancellableOperation.value.whenComplete(() => {
          print('onDone'),
        });
    cancellableOperation.cancel(); // <- commment this if you want to complete

CancelableFuture 例子

    final delayedFuture = ...;

    final cancalableFuture = CancelableFuture<String>(
      future: delayedFuture,
      onComplete: (result) {
        // Use the result from the future to do stuff
        print(result);
      },
    );
    cancalableFuture.cancel(); // <- commment this if you want to complete

以及 CancelableFuture 实现

class CancelableFuture<T> {
  bool _cancelled = false;
  CancelableFuture({
    @required Future<dynamic> future,
    @required void Function(T) onComplete,
  }) {
    future.then((value) {
      if (!_cancelled) onComplete(value);
    });
  }
  void cancel() {
    _cancelled = true;
  }
}

您无法取消现有 Future。如果你这样做:

Future.delayed(
  Duration(seconds: 2),
  () {
    print('hello');
  },
);

只要进程运行(并正在处理其事件队列)至少 2 秒,Future 最终将执行并打印 'hello'

充其量您可以导致 Future 的完成回调之一过早触发,以便调用者可以将操作视为已取消或失败,这就是 CancelableOperation 等。做。

编辑:

根据您更新的问题,现在具体询问 delayed Futures,您应该考虑使用 Timer可取消。 (但是,与 Future 不同,呼叫者不能直接等待 Timer。如果这对您很重要,您需要创建一个 Completer,让呼叫者在 CompleterFuture,让Timer的回调完成。)

使用定时器:

var t = Timer(Duration(seconds: 400), () async {
   client.close(force: true);
});
...
t.cancel();