【问题标题】:How to make a delayed future cancelable in Dart?如何在 Dart 中取消延迟的未来?
【发布时间】:2021-05-28 12:38:54
【问题描述】:

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

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

请注意,操作本身不是异步的并且是无效的——不返回任何内容。

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

我已经开始这样做了:

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()}) 创建一个 CancelableOperation 包装内部。 [...] 工厂

但老实说,这只是让我可怜的头疼得厉害。

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

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

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

谢谢。

【问题讨论】:

  • 您是否愿意接受其他不使用 CancelableOperation 的建议?
  • @YoBo 我想知道

标签: flutter dart asynchronous future


【解决方案1】:

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

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

【讨论】:

  • 所以我看到了如何使用 .cancel() 取消 CancelableFuture,但是首先如何启动/运行它呢?可取消Future.run()? no.cancelableFuture()?不。 :S
  • 您在这里经营未来:Future.delayed(。您只是传递 Future 并且如果您取消,onComplete 将不会触发。而已。也许我没有得到正确的问题。您到底想对需要取消的 Future 做什么?您能否提供更多信息,以便我们尝试提出解决方案。
  • 不,我确定你没看错。这个问题不是很好。我会稍微编辑一下。我很困惑,主要是因为我只是想把它们放在 dartpad 中所以我理解它,但是我遇到了我不理解的错误。
【解决方案2】:

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

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

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

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

编辑:

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

【讨论】:

    【解决方案3】:

    使用计时器:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-20
      • 1970-01-01
      • 1970-01-01
      • 2023-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-25
      相关资源
      最近更新 更多